mirror of https://github.com/docker/docs.git
Update digital ocean dependencies
Signed-off-by: David Gageot <david@gageot.net>
This commit is contained in:
parent
480051c1f7
commit
198ab07be0
|
|
@ -68,8 +68,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/digitalocean/godo",
|
"ImportPath": "github.com/digitalocean/godo",
|
||||||
"Comment": "v0.5.0",
|
"Comment": "v0.9.0-8-g2124bf3",
|
||||||
"Rev": "5478aae80694de1d2d0e02c386bbedd201266234"
|
"Rev": "2124bf3eeeb4ac070337bb19ef7b76a745de56f4"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/docker/docker/pkg/term",
|
"ImportPath": "github.com/docker/docker/pkg/term",
|
||||||
|
|
|
||||||
|
|
@ -158,14 +158,14 @@ func (d *Driver) Create() error {
|
||||||
client := d.getClient()
|
client := d.getClient()
|
||||||
|
|
||||||
createRequest := &godo.DropletCreateRequest{
|
createRequest := &godo.DropletCreateRequest{
|
||||||
Image: d.Image,
|
Image: godo.DropletCreateImage{Slug: d.Image},
|
||||||
Name: d.MachineName,
|
Name: d.MachineName,
|
||||||
Region: d.Region,
|
Region: d.Region,
|
||||||
Size: d.Size,
|
Size: d.Size,
|
||||||
IPv6: d.IPv6,
|
IPv6: d.IPv6,
|
||||||
PrivateNetworking: d.PrivateNetworking,
|
PrivateNetworking: d.PrivateNetworking,
|
||||||
Backups: d.Backups,
|
Backups: d.Backups,
|
||||||
SSHKeys: []interface{}{d.SSHKeyID},
|
SSHKeys: []godo.DropletCreateSSHKey{{ID: d.SSHKeyID}},
|
||||||
}
|
}
|
||||||
|
|
||||||
newDroplet, _, err := client.Droplets.Create(createRequest)
|
newDroplet, _, err := client.Droplets.Create(createRequest)
|
||||||
|
|
@ -173,7 +173,7 @@ func (d *Driver) Create() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
d.DropletID = newDroplet.Droplet.ID
|
d.DropletID = newDroplet.ID
|
||||||
|
|
||||||
log.Info("Waiting for IP address to be assigned to the Droplet...")
|
log.Info("Waiting for IP address to be assigned to the Droplet...")
|
||||||
for {
|
for {
|
||||||
|
|
@ -181,7 +181,7 @@ func (d *Driver) Create() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, network := range newDroplet.Droplet.Networks.V4 {
|
for _, network := range newDroplet.Networks.V4 {
|
||||||
if network.Type == "public" {
|
if network.Type == "public" {
|
||||||
d.IPAddress = network.IPAddress
|
d.IPAddress = network.IPAddress
|
||||||
}
|
}
|
||||||
|
|
@ -195,7 +195,7 @@ func (d *Driver) Create() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Created droplet ID %d, IP address %s",
|
log.Debugf("Created droplet ID %d, IP address %s",
|
||||||
newDroplet.Droplet.ID,
|
newDroplet.ID,
|
||||||
d.IPAddress)
|
d.IPAddress)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -237,7 +237,7 @@ func (d *Driver) GetState() (state.State, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return state.Error, err
|
return state.Error, err
|
||||||
}
|
}
|
||||||
switch droplet.Droplet.Status {
|
switch droplet.Status {
|
||||||
case "new":
|
case "new":
|
||||||
return state.Starting, nil
|
return state.Starting, nil
|
||||||
case "active":
|
case "active":
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.3
|
||||||
|
- 1.4
|
||||||
|
- tip
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Contributing
|
||||||
|
|
||||||
|
If you submit a pull request, please keep the following guidelines in mind:
|
||||||
|
|
||||||
|
1. Code should be `go fmt` compliant.
|
||||||
|
2. Types, structs and funcs should be documented.
|
||||||
|
3. Tests pass.
|
||||||
|
|
||||||
|
## Getting set up
|
||||||
|
|
||||||
|
Assuming your `$GOPATH` is set up according to your desires, run:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go get github.com/digitalocean/godo
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running tests
|
||||||
|
|
||||||
|
When working on code in this repository, tests can be run via:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go test .
|
||||||
|
```
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
OPEN = $(shell which xdg-open || which gnome-open || which open)
|
|
||||||
|
|
||||||
cov:
|
|
||||||
@@gocov test | gocov-html > /tmp/coverage.html
|
|
||||||
@@${OPEN} /tmp/coverage.html
|
|
||||||
|
|
||||||
ci:
|
|
||||||
go get -d -v -t ./...
|
|
||||||
go build ./...
|
|
||||||
go test -v ./...
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
|
[](https://travis-ci.org/digitalocean/godo)
|
||||||
|
|
||||||
# Godo
|
# Godo
|
||||||
|
|
||||||
Godo is a Go client library for accessing the DigitalOcean V2 API.
|
Godo is a Go client library for accessing the DigitalOcean V2 API.
|
||||||
|
|
||||||
You can view the client API docs here: [http://godoc.org/github.com/digitalocean/godo](http://godoc.org/github.com/digitalocean/godo)
|
You can view the client API docs here: [http://godoc.org/github.com/digitalocean/godo](http://godoc.org/github.com/digitalocean/godo)
|
||||||
|
|
||||||
You can view Digital Ocean API docs here: [https://developers.digitalocean.com/v2/](https://developers.digitalocean.com/v2/)
|
You can view DigitalOcean API docs here: [https://developers.digitalocean.com/documentation/v2/](https://developers.digitalocean.com/documentation/v2/)
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
@ -20,19 +22,30 @@ access different parts of the DigitalOcean API.
|
||||||
|
|
||||||
Currently, Personal Access Token (PAT) is the only method of
|
Currently, Personal Access Token (PAT) is the only method of
|
||||||
authenticating with the API. You can manage your tokens
|
authenticating with the API. You can manage your tokens
|
||||||
at the Digital Ocean Control Panel [Applications Page](https://cloud.digitalocean.com/settings/applications).
|
at the DigitalOcean Control Panel [Applications Page](https://cloud.digitalocean.com/settings/applications).
|
||||||
|
|
||||||
You can then use your token to create a new client:
|
You can then use your token to create a new client:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "code.google.com/p/goauth2/oauth"
|
import "golang.org/x/oauth2"
|
||||||
|
|
||||||
pat := "mytoken"
|
pat := "mytoken"
|
||||||
t := &oauth.Transport{
|
type TokenSource struct {
|
||||||
Token: &oauth.Token{AccessToken: pat},
|
AccessToken string
|
||||||
}
|
}
|
||||||
|
|
||||||
client := godo.NewClient(t.Client())
|
func (t *TokenSource) Token() (*oauth2.Token, error) {
|
||||||
|
token := &oauth2.Token{
|
||||||
|
AccessToken: t.AccessToken,
|
||||||
|
}
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenSource := &TokenSource{
|
||||||
|
AccessToken: pat,
|
||||||
|
}
|
||||||
|
oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource)
|
||||||
|
client := godo.NewClient(oauthClient)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
@ -47,7 +60,9 @@ createRequest := &godo.DropletCreateRequest{
|
||||||
Name: dropletName,
|
Name: dropletName,
|
||||||
Region: "nyc3",
|
Region: "nyc3",
|
||||||
Size: "512mb",
|
Size: "512mb",
|
||||||
Image: "ubuntu-14-04-x64",
|
Image: godo.DropletCreateImage{
|
||||||
|
Slug: "ubuntu-14-04-x64",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
newDroplet, _, err := client.Droplets.Create(createRequest)
|
newDroplet, _, err := client.Droplets.Create(createRequest)
|
||||||
|
|
@ -72,29 +87,50 @@ func DropletList(client *godo.Client) ([]godo.Droplet, error) {
|
||||||
for {
|
for {
|
||||||
droplets, resp, err := client.Droplets.List(opt)
|
droplets, resp, err := client.Droplets.List(opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// append the current page's droplets to our list
|
// append the current page's droplets to our list
|
||||||
for _, d := range droplets {
|
for _, d := range droplets {
|
||||||
list = append(list, d)
|
list = append(list, d)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we are at the last page, break out the for loop
|
// if we are at the last page, break out the for loop
|
||||||
if resp.Links.IsLastPage() {
|
if resp.Links == nil || resp.Links.IsLastPage() {
|
||||||
break
|
break
|
||||||
}
|
|
||||||
|
|
||||||
page, err := resp.Links.CurrentPage()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the page we want for the next request
|
page, err := resp.Links.CurrentPage()
|
||||||
opt.Page = page + 1
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the page we want for the next request
|
||||||
|
opt.Page = page + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return list, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Versioning
|
||||||
|
|
||||||
|
Each version of the client is tagged and the version is updated accordingly.
|
||||||
|
|
||||||
|
Since Go does not have a built-in versioning, a package management tool is
|
||||||
|
recommended - a good one that works with git tags is
|
||||||
|
[gopkg.in](http://labix.org/gopkg.in).
|
||||||
|
|
||||||
|
To see the list of past versions, run `git tag`.
|
||||||
|
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
For a comprehensive list of examples, check out the [API documentation](https://developers.digitalocean.com/documentation/v2/).
|
||||||
|
|
||||||
|
For details on all the functionality in this library, see the [GoDoc](http://godoc.org/github.com/digitalocean/godo) documentation.
|
||||||
|
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
We love pull requests! Please see the [contribution guidelines](CONTRIBUTING.md).
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
package godo
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccountServiceOp handles communication with the Account related methods of
|
||||||
|
// the DigitalOcean API.
|
||||||
|
type AccountServiceOp struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ AccountService = &AccountServiceOp{}
|
||||||
|
|
||||||
|
// Account represents a DigitalOcean Account
|
||||||
|
type Account struct {
|
||||||
|
DropletLimit int `json:"droplet_limit,omitempty"`
|
||||||
|
Email string `json:"email,omitempty"`
|
||||||
|
UUID string `json:"uuid,omitempty"`
|
||||||
|
EmailVerified bool `json:"email_verified,omitempty"`
|
||||||
|
Status string `json:"status,omitempty"`
|
||||||
|
StatusMessage string `json:"status_message,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type accountRoot struct {
|
||||||
|
Account *Account `json:"account"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Account) String() string {
|
||||||
|
return Stringify(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get DigitalOcean account info
|
||||||
|
func (s *AccountServiceOp) Get() (*Account, *Response, error) {
|
||||||
|
path := "v2/account"
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
root := new(accountRoot)
|
||||||
|
resp, err := s.client.Do(req, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return root.Account, resp, err
|
||||||
|
}
|
||||||
|
|
@ -13,7 +13,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// ActionsService handles communction with action related methods of the
|
// ActionsService handles communction with action related methods of the
|
||||||
// DigitalOcean API: https://developers.digitalocean.com/#actions
|
// DigitalOcean API: https://developers.digitalocean.com/documentation/v2#actions
|
||||||
type ActionsService interface {
|
type ActionsService interface {
|
||||||
List(*ListOptions) ([]Action, *Response, error)
|
List(*ListOptions) ([]Action, *Response, error)
|
||||||
Get(int) (*Action, *Response, error)
|
Get(int) (*Action, *Response, error)
|
||||||
|
|
@ -25,6 +25,8 @@ type ActionsServiceOp struct {
|
||||||
client *Client
|
client *Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ ActionsService = &ActionsServiceOp{}
|
||||||
|
|
||||||
type actionsRoot struct {
|
type actionsRoot struct {
|
||||||
Actions []Action `json:"actions"`
|
Actions []Action `json:"actions"`
|
||||||
Links *Links `json:"links"`
|
Links *Links `json:"links"`
|
||||||
|
|
@ -43,6 +45,8 @@ type Action struct {
|
||||||
CompletedAt *Timestamp `json:"completed_at"`
|
CompletedAt *Timestamp `json:"completed_at"`
|
||||||
ResourceID int `json:"resource_id"`
|
ResourceID int `json:"resource_id"`
|
||||||
ResourceType string `json:"resource_type"`
|
ResourceType string `json:"resource_type"`
|
||||||
|
Region *Region `json:"region,omitempty"`
|
||||||
|
RegionSlug string `json:"region_slug,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// List all actions
|
// List all actions
|
||||||
|
|
@ -70,8 +74,12 @@ func (s *ActionsServiceOp) List(opt *ListOptions) ([]Action, *Response, error) {
|
||||||
return root.Actions, resp, err
|
return root.Actions, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get an action by ID
|
// Get an action by ID.
|
||||||
func (s *ActionsServiceOp) Get(id int) (*Action, *Response, error) {
|
func (s *ActionsServiceOp) Get(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)
|
path := fmt.Sprintf("%s/%d", actionsBasePath, id)
|
||||||
req, err := s.client.NewRequest("GET", path, nil)
|
req, err := s.client.NewRequest("GET", path, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
package godo
|
|
||||||
|
|
||||||
// ActionRequest reprents DigitalOcean Action Request
|
|
||||||
type ActionRequest struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
Params map[string]interface{} `json:"params,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Converts an ActionRequest to a string.
|
|
||||||
func (d ActionRequest) String() string {
|
|
||||||
return Stringify(d)
|
|
||||||
}
|
|
||||||
|
|
@ -4,13 +4,13 @@ import "fmt"
|
||||||
|
|
||||||
const domainsBasePath = "v2/domains"
|
const domainsBasePath = "v2/domains"
|
||||||
|
|
||||||
// DomainsService is an interface for managing DNS with the Digital Ocean API.
|
// DomainsService is an interface for managing DNS with the DigitalOcean API.
|
||||||
// See: https://developers.digitalocean.com/#domains and
|
// See: https://developers.digitalocean.com/documentation/v2#domains and
|
||||||
// https://developers.digitalocean.com/#domain-records
|
// https://developers.digitalocean.com/documentation/v2#domain-records
|
||||||
type DomainsService interface {
|
type DomainsService interface {
|
||||||
List(*ListOptions) ([]Domain, *Response, error)
|
List(*ListOptions) ([]Domain, *Response, error)
|
||||||
Get(string) (*DomainRoot, *Response, error)
|
Get(string) (*Domain, *Response, error)
|
||||||
Create(*DomainCreateRequest) (*DomainRoot, *Response, error)
|
Create(*DomainCreateRequest) (*Domain, *Response, error)
|
||||||
Delete(string) (*Response, error)
|
Delete(string) (*Response, error)
|
||||||
|
|
||||||
Records(string, *ListOptions) ([]DomainRecord, *Response, error)
|
Records(string, *ListOptions) ([]DomainRecord, *Response, error)
|
||||||
|
|
@ -26,15 +26,17 @@ type DomainsServiceOp struct {
|
||||||
client *Client
|
client *Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// Domain represents a Digital Ocean domain
|
var _ DomainsService = &DomainsServiceOp{}
|
||||||
|
|
||||||
|
// Domain represents a DigitalOcean domain
|
||||||
type Domain struct {
|
type Domain struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
TTL int `json:"ttl"`
|
TTL int `json:"ttl"`
|
||||||
ZoneFile string `json:"zone_file"`
|
ZoneFile string `json:"zone_file"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DomainRoot represents a response from the Digital Ocean API
|
// domainRoot represents a response from the DigitalOcean API
|
||||||
type DomainRoot struct {
|
type domainRoot struct {
|
||||||
Domain *Domain `json:"domain"`
|
Domain *Domain `json:"domain"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,12 +52,12 @@ type DomainCreateRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DomainRecordRoot is the root of an individual Domain Record response
|
// DomainRecordRoot is the root of an individual Domain Record response
|
||||||
type DomainRecordRoot struct {
|
type domainRecordRoot struct {
|
||||||
DomainRecord *DomainRecord `json:"domain_record"`
|
DomainRecord *DomainRecord `json:"domain_record"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DomainRecordsRoot is the root of a group of Domain Record responses
|
// DomainRecordsRoot is the root of a group of Domain Record responses
|
||||||
type DomainRecordsRoot struct {
|
type domainRecordsRoot struct {
|
||||||
DomainRecords []DomainRecord `json:"domain_records"`
|
DomainRecords []DomainRecord `json:"domain_records"`
|
||||||
Links *Links `json:"links"`
|
Links *Links `json:"links"`
|
||||||
}
|
}
|
||||||
|
|
@ -85,7 +87,7 @@ func (d Domain) String() string {
|
||||||
return Stringify(d)
|
return Stringify(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List all domains
|
// List all domains.
|
||||||
func (s DomainsServiceOp) List(opt *ListOptions) ([]Domain, *Response, error) {
|
func (s DomainsServiceOp) List(opt *ListOptions) ([]Domain, *Response, error) {
|
||||||
path := domainsBasePath
|
path := domainsBasePath
|
||||||
path, err := addOptions(path, opt)
|
path, err := addOptions(path, opt)
|
||||||
|
|
@ -110,8 +112,12 @@ func (s DomainsServiceOp) List(opt *ListOptions) ([]Domain, *Response, error) {
|
||||||
return root.Domains, resp, err
|
return root.Domains, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get individual domain
|
// Get individual domain. It requires a non-empty domain name.
|
||||||
func (s *DomainsServiceOp) Get(name string) (*DomainRoot, *Response, error) {
|
func (s *DomainsServiceOp) Get(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)
|
path := fmt.Sprintf("%s/%s", domainsBasePath, name)
|
||||||
|
|
||||||
req, err := s.client.NewRequest("GET", path, nil)
|
req, err := s.client.NewRequest("GET", path, nil)
|
||||||
|
|
@ -119,17 +125,21 @@ func (s *DomainsServiceOp) Get(name string) (*DomainRoot, *Response, error) {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
root := new(DomainRoot)
|
root := new(domainRoot)
|
||||||
resp, err := s.client.Do(req, root)
|
resp, err := s.client.Do(req, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, resp, err
|
return nil, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return root, resp, err
|
return root.Domain, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new domain
|
// Create a new domain
|
||||||
func (s *DomainsServiceOp) Create(createRequest *DomainCreateRequest) (*DomainRoot, *Response, error) {
|
func (s *DomainsServiceOp) Create(createRequest *DomainCreateRequest) (*Domain, *Response, error) {
|
||||||
|
if createRequest == nil {
|
||||||
|
return nil, nil, NewArgError("createRequest", "cannot be nil")
|
||||||
|
}
|
||||||
|
|
||||||
path := domainsBasePath
|
path := domainsBasePath
|
||||||
|
|
||||||
req, err := s.client.NewRequest("POST", path, createRequest)
|
req, err := s.client.NewRequest("POST", path, createRequest)
|
||||||
|
|
@ -137,17 +147,20 @@ func (s *DomainsServiceOp) Create(createRequest *DomainCreateRequest) (*DomainRo
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
root := new(DomainRoot)
|
root := new(domainRoot)
|
||||||
resp, err := s.client.Do(req, root)
|
resp, err := s.client.Do(req, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, resp, err
|
return nil, resp, err
|
||||||
}
|
}
|
||||||
|
return root.Domain, resp, err
|
||||||
return root, resp, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete droplet
|
// Delete domain
|
||||||
func (s *DomainsServiceOp) Delete(name string) (*Response, error) {
|
func (s *DomainsServiceOp) Delete(name string) (*Response, error) {
|
||||||
|
if len(name) < 1 {
|
||||||
|
return nil, NewArgError("name", "cannot be an empty string")
|
||||||
|
}
|
||||||
|
|
||||||
path := fmt.Sprintf("%s/%s", domainsBasePath, name)
|
path := fmt.Sprintf("%s/%s", domainsBasePath, name)
|
||||||
|
|
||||||
req, err := s.client.NewRequest("DELETE", path, nil)
|
req, err := s.client.NewRequest("DELETE", path, nil)
|
||||||
|
|
@ -172,6 +185,10 @@ func (d DomainRecordEditRequest) String() string {
|
||||||
|
|
||||||
// Records returns a slice of DomainRecords for a domain
|
// Records returns a slice of DomainRecords for a domain
|
||||||
func (s *DomainsServiceOp) Records(domain string, opt *ListOptions) ([]DomainRecord, *Response, error) {
|
func (s *DomainsServiceOp) Records(domain string, opt *ListOptions) ([]DomainRecord, *Response, error) {
|
||||||
|
if len(domain) < 1 {
|
||||||
|
return nil, nil, NewArgError("domain", "cannot be an empty string")
|
||||||
|
}
|
||||||
|
|
||||||
path := fmt.Sprintf("%s/%s/records", domainsBasePath, domain)
|
path := fmt.Sprintf("%s/%s/records", domainsBasePath, domain)
|
||||||
path, err := addOptions(path, opt)
|
path, err := addOptions(path, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -183,7 +200,7 @@ func (s *DomainsServiceOp) Records(domain string, opt *ListOptions) ([]DomainRec
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
root := new(DomainRecordsRoot)
|
root := new(domainRecordsRoot)
|
||||||
resp, err := s.client.Do(req, root)
|
resp, err := s.client.Do(req, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, resp, err
|
return nil, resp, err
|
||||||
|
|
@ -197,6 +214,14 @@ func (s *DomainsServiceOp) Records(domain string, opt *ListOptions) ([]DomainRec
|
||||||
|
|
||||||
// Record returns the record id from a domain
|
// Record returns the record id from a domain
|
||||||
func (s *DomainsServiceOp) Record(domain string, id int) (*DomainRecord, *Response, error) {
|
func (s *DomainsServiceOp) Record(domain string, id int) (*DomainRecord, *Response, error) {
|
||||||
|
if len(domain) < 1 {
|
||||||
|
return nil, nil, NewArgError("domain", "cannot be an empty string")
|
||||||
|
}
|
||||||
|
|
||||||
|
if id < 1 {
|
||||||
|
return nil, nil, NewArgError("id", "cannot be less than 1")
|
||||||
|
}
|
||||||
|
|
||||||
path := fmt.Sprintf("%s/%s/records/%d", domainsBasePath, domain, id)
|
path := fmt.Sprintf("%s/%s/records/%d", domainsBasePath, domain, id)
|
||||||
|
|
||||||
req, err := s.client.NewRequest("GET", path, nil)
|
req, err := s.client.NewRequest("GET", path, nil)
|
||||||
|
|
@ -204,7 +229,7 @@ func (s *DomainsServiceOp) Record(domain string, id int) (*DomainRecord, *Respon
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
record := new(DomainRecordRoot)
|
record := new(domainRecordRoot)
|
||||||
resp, err := s.client.Do(req, record)
|
resp, err := s.client.Do(req, record)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, resp, err
|
return nil, resp, err
|
||||||
|
|
@ -215,6 +240,14 @@ func (s *DomainsServiceOp) Record(domain string, id int) (*DomainRecord, *Respon
|
||||||
|
|
||||||
// DeleteRecord deletes a record from a domain identified by id
|
// DeleteRecord deletes a record from a domain identified by id
|
||||||
func (s *DomainsServiceOp) DeleteRecord(domain string, id int) (*Response, error) {
|
func (s *DomainsServiceOp) DeleteRecord(domain string, id int) (*Response, error) {
|
||||||
|
if len(domain) < 1 {
|
||||||
|
return nil, NewArgError("domain", "cannot be an empty string")
|
||||||
|
}
|
||||||
|
|
||||||
|
if id < 1 {
|
||||||
|
return nil, NewArgError("id", "cannot be less than 1")
|
||||||
|
}
|
||||||
|
|
||||||
path := fmt.Sprintf("%s/%s/records/%d", domainsBasePath, domain, id)
|
path := fmt.Sprintf("%s/%s/records/%d", domainsBasePath, domain, id)
|
||||||
|
|
||||||
req, err := s.client.NewRequest("DELETE", path, nil)
|
req, err := s.client.NewRequest("DELETE", path, nil)
|
||||||
|
|
@ -231,7 +264,20 @@ func (s *DomainsServiceOp) DeleteRecord(domain string, id int) (*Response, error
|
||||||
func (s *DomainsServiceOp) EditRecord(
|
func (s *DomainsServiceOp) EditRecord(
|
||||||
domain string,
|
domain string,
|
||||||
id int,
|
id int,
|
||||||
editRequest *DomainRecordEditRequest) (*DomainRecord, *Response, error) {
|
editRequest *DomainRecordEditRequest,
|
||||||
|
) (*DomainRecord, *Response, error) {
|
||||||
|
if len(domain) < 1 {
|
||||||
|
return nil, nil, NewArgError("domain", "cannot be an empty string")
|
||||||
|
}
|
||||||
|
|
||||||
|
if id < 1 {
|
||||||
|
return nil, nil, NewArgError("id", "cannot be less than 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
if editRequest == nil {
|
||||||
|
return nil, nil, NewArgError("editRequest", "cannot be nil")
|
||||||
|
}
|
||||||
|
|
||||||
path := fmt.Sprintf("%s/%s/records/%d", domainsBasePath, domain, id)
|
path := fmt.Sprintf("%s/%s/records/%d", domainsBasePath, domain, id)
|
||||||
|
|
||||||
req, err := s.client.NewRequest("PUT", path, editRequest)
|
req, err := s.client.NewRequest("PUT", path, editRequest)
|
||||||
|
|
@ -252,6 +298,14 @@ func (s *DomainsServiceOp) EditRecord(
|
||||||
func (s *DomainsServiceOp) CreateRecord(
|
func (s *DomainsServiceOp) CreateRecord(
|
||||||
domain string,
|
domain string,
|
||||||
createRequest *DomainRecordEditRequest) (*DomainRecord, *Response, error) {
|
createRequest *DomainRecordEditRequest) (*DomainRecord, *Response, error) {
|
||||||
|
if len(domain) < 1 {
|
||||||
|
return nil, nil, NewArgError("domain", "cannot be empty string")
|
||||||
|
}
|
||||||
|
|
||||||
|
if createRequest == nil {
|
||||||
|
return nil, nil, NewArgError("createRequest", "cannot be nil")
|
||||||
|
}
|
||||||
|
|
||||||
path := fmt.Sprintf("%s/%s/records", domainsBasePath, domain)
|
path := fmt.Sprintf("%s/%s/records", domainsBasePath, domain)
|
||||||
req, err := s.client.NewRequest("POST", path, createRequest)
|
req, err := s.client.NewRequest("POST", path, createRequest)
|
||||||
|
|
||||||
|
|
@ -259,7 +313,7 @@ func (s *DomainsServiceOp) CreateRecord(
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
d := new(DomainRecordRoot)
|
d := new(domainRecordRoot)
|
||||||
resp, err := s.client.Do(req, d)
|
resp, err := s.client.Do(req, d)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, resp, err
|
return nil, resp, err
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,12 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ActionRequest reprents DigitalOcean Action Request
|
||||||
|
type ActionRequest map[string]interface{}
|
||||||
|
|
||||||
// DropletActionsService is an interface for interfacing with the droplet actions
|
// DropletActionsService is an interface for interfacing with the droplet actions
|
||||||
// endpoints of the Digital Ocean API
|
// endpoints of the DigitalOcean API
|
||||||
// See: https://developers.digitalocean.com/#droplet-actions
|
// See: https://developers.digitalocean.com/documentation/v2#droplet-actions
|
||||||
type DropletActionsService interface {
|
type DropletActionsService interface {
|
||||||
Shutdown(int) (*Action, *Response, error)
|
Shutdown(int) (*Action, *Response, error)
|
||||||
PowerOff(int) (*Action, *Response, error)
|
PowerOff(int) (*Action, *Response, error)
|
||||||
|
|
@ -15,9 +18,18 @@ type DropletActionsService interface {
|
||||||
PowerCycle(int) (*Action, *Response, error)
|
PowerCycle(int) (*Action, *Response, error)
|
||||||
Reboot(int) (*Action, *Response, error)
|
Reboot(int) (*Action, *Response, error)
|
||||||
Restore(int, int) (*Action, *Response, error)
|
Restore(int, int) (*Action, *Response, error)
|
||||||
Resize(int, string) (*Action, *Response, error)
|
Resize(int, string, bool) (*Action, *Response, error)
|
||||||
Rename(int, string) (*Action, *Response, error)
|
Rename(int, string) (*Action, *Response, error)
|
||||||
doAction(int, *ActionRequest) (*Action, *Response, error)
|
Snapshot(int, string) (*Action, *Response, error)
|
||||||
|
EnableBackups(int) (*Action, *Response, error)
|
||||||
|
DisableBackups(int) (*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)
|
||||||
|
EnablePrivateNetworking(int) (*Action, *Response, error)
|
||||||
|
Upgrade(int) (*Action, *Response, error)
|
||||||
Get(int, int) (*Action, *Response, error)
|
Get(int, int) (*Action, *Response, error)
|
||||||
GetByURI(string) (*Action, *Response, error)
|
GetByURI(string) (*Action, *Response, error)
|
||||||
}
|
}
|
||||||
|
|
@ -28,79 +40,142 @@ type DropletActionsServiceOp struct {
|
||||||
client *Client
|
client *Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ DropletActionsService = &DropletActionsServiceOp{}
|
||||||
|
|
||||||
// Shutdown a Droplet
|
// Shutdown a Droplet
|
||||||
func (s *DropletActionsServiceOp) Shutdown(id int) (*Action, *Response, error) {
|
func (s *DropletActionsServiceOp) Shutdown(id int) (*Action, *Response, error) {
|
||||||
request := &ActionRequest{Type: "shutdown"}
|
request := &ActionRequest{"type": "shutdown"}
|
||||||
return s.doAction(id, request)
|
return s.doAction(id, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PowerOff a Droplet
|
// PowerOff a Droplet
|
||||||
func (s *DropletActionsServiceOp) PowerOff(id int) (*Action, *Response, error) {
|
func (s *DropletActionsServiceOp) PowerOff(id int) (*Action, *Response, error) {
|
||||||
request := &ActionRequest{Type: "power_off"}
|
request := &ActionRequest{"type": "power_off"}
|
||||||
return s.doAction(id, request)
|
return s.doAction(id, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PowerOn a Droplet
|
// PowerOn a Droplet
|
||||||
func (s *DropletActionsServiceOp) PowerOn(id int) (*Action, *Response, error) {
|
func (s *DropletActionsServiceOp) PowerOn(id int) (*Action, *Response, error) {
|
||||||
request := &ActionRequest{Type: "power_on"}
|
request := &ActionRequest{"type": "power_on"}
|
||||||
return s.doAction(id, request)
|
return s.doAction(id, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PowerCycle a Droplet
|
// PowerCycle a Droplet
|
||||||
func (s *DropletActionsServiceOp) PowerCycle(id int) (*Action, *Response, error) {
|
func (s *DropletActionsServiceOp) PowerCycle(id int) (*Action, *Response, error) {
|
||||||
request := &ActionRequest{Type: "power_cycle"}
|
request := &ActionRequest{"type": "power_cycle"}
|
||||||
return s.doAction(id, request)
|
return s.doAction(id, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reboot a Droplet
|
// Reboot a Droplet
|
||||||
func (s *DropletActionsServiceOp) Reboot(id int) (*Action, *Response, error) {
|
func (s *DropletActionsServiceOp) Reboot(id int) (*Action, *Response, error) {
|
||||||
request := &ActionRequest{Type: "reboot"}
|
request := &ActionRequest{"type": "reboot"}
|
||||||
return s.doAction(id, request)
|
return s.doAction(id, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore an image to a Droplet
|
// Restore an image to a Droplet
|
||||||
func (s *DropletActionsServiceOp) Restore(id, imageID int) (*Action, *Response, error) {
|
func (s *DropletActionsServiceOp) Restore(id, imageID int) (*Action, *Response, error) {
|
||||||
options := map[string]interface{}{
|
|
||||||
"image": float64(imageID),
|
|
||||||
}
|
|
||||||
|
|
||||||
requestType := "restore"
|
requestType := "restore"
|
||||||
request := &ActionRequest{
|
request := &ActionRequest{
|
||||||
Type: requestType,
|
"type": requestType,
|
||||||
Params: options,
|
"image": float64(imageID),
|
||||||
}
|
}
|
||||||
return s.doAction(id, request)
|
return s.doAction(id, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resize a Droplet
|
// Resize a Droplet
|
||||||
func (s *DropletActionsServiceOp) Resize(id int, sizeSlug string) (*Action, *Response, error) {
|
func (s *DropletActionsServiceOp) Resize(id int, sizeSlug string, resizeDisk bool) (*Action, *Response, error) {
|
||||||
options := map[string]interface{}{
|
|
||||||
"size": sizeSlug,
|
|
||||||
}
|
|
||||||
|
|
||||||
requestType := "resize"
|
requestType := "resize"
|
||||||
request := &ActionRequest{
|
request := &ActionRequest{
|
||||||
Type: requestType,
|
"type": requestType,
|
||||||
Params: options,
|
"size": sizeSlug,
|
||||||
|
"disk": resizeDisk,
|
||||||
}
|
}
|
||||||
return s.doAction(id, request)
|
return s.doAction(id, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rename a Droplet
|
// Rename a Droplet
|
||||||
func (s *DropletActionsServiceOp) Rename(id int, name string) (*Action, *Response, error) {
|
func (s *DropletActionsServiceOp) Rename(id int, name string) (*Action, *Response, error) {
|
||||||
options := map[string]interface{}{
|
|
||||||
"name": name,
|
|
||||||
}
|
|
||||||
|
|
||||||
requestType := "rename"
|
requestType := "rename"
|
||||||
request := &ActionRequest{
|
request := &ActionRequest{
|
||||||
Type: requestType,
|
"type": requestType,
|
||||||
Params: options,
|
"name": name,
|
||||||
}
|
}
|
||||||
return s.doAction(id, request)
|
return s.doAction(id, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Snapshot a Droplet.
|
||||||
|
func (s *DropletActionsServiceOp) Snapshot(id int, name string) (*Action, *Response, error) {
|
||||||
|
requestType := "snapshot"
|
||||||
|
request := &ActionRequest{
|
||||||
|
"type": requestType,
|
||||||
|
"name": name,
|
||||||
|
}
|
||||||
|
return s.doAction(id, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableBackups enables backups for a droplet.
|
||||||
|
func (s *DropletActionsServiceOp) EnableBackups(id int) (*Action, *Response, error) {
|
||||||
|
request := &ActionRequest{"type": "enable_backups"}
|
||||||
|
return s.doAction(id, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableBackups disables backups for a droplet.
|
||||||
|
func (s *DropletActionsServiceOp) DisableBackups(id int) (*Action, *Response, error) {
|
||||||
|
request := &ActionRequest{"type": "disable_backups"}
|
||||||
|
return s.doAction(id, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PasswordReset resets the password for a droplet.
|
||||||
|
func (s *DropletActionsServiceOp) PasswordReset(id int) (*Action, *Response, error) {
|
||||||
|
request := &ActionRequest{"type": "password_reset"}
|
||||||
|
return s.doAction(id, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RebuildByImageID rebuilds a droplet droplet from an image with a given id.
|
||||||
|
func (s *DropletActionsServiceOp) RebuildByImageID(id, imageID int) (*Action, *Response, error) {
|
||||||
|
request := &ActionRequest{"type": "rebuild", "image": imageID}
|
||||||
|
return s.doAction(id, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RebuildByImageSlug rebuilds a droplet from an image with a given slug.
|
||||||
|
func (s *DropletActionsServiceOp) RebuildByImageSlug(id int, slug string) (*Action, *Response, error) {
|
||||||
|
request := &ActionRequest{"type": "rebuild", "image": slug}
|
||||||
|
return s.doAction(id, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangeKernel changes the kernel for a droplet.
|
||||||
|
func (s *DropletActionsServiceOp) ChangeKernel(id, kernelID int) (*Action, *Response, error) {
|
||||||
|
request := &ActionRequest{"type": "change_kernel", "kernel": kernelID}
|
||||||
|
return s.doAction(id, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableIPv6 enables IPv6 for a droplet.
|
||||||
|
func (s *DropletActionsServiceOp) EnableIPv6(id int) (*Action, *Response, error) {
|
||||||
|
request := &ActionRequest{"type": "enable_ipv6"}
|
||||||
|
return s.doAction(id, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnablePrivateNetworking enables private networking for a droplet.
|
||||||
|
func (s *DropletActionsServiceOp) EnablePrivateNetworking(id int) (*Action, *Response, error) {
|
||||||
|
request := &ActionRequest{"type": "enable_private_networking"}
|
||||||
|
return s.doAction(id, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upgrade a droplet.
|
||||||
|
func (s *DropletActionsServiceOp) Upgrade(id int) (*Action, *Response, error) {
|
||||||
|
request := &ActionRequest{"type": "upgrade"}
|
||||||
|
return s.doAction(id, request)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *DropletActionsServiceOp) doAction(id int, request *ActionRequest) (*Action, *Response, error) {
|
func (s *DropletActionsServiceOp) doAction(id int, request *ActionRequest) (*Action, *Response, error) {
|
||||||
|
if id < 1 {
|
||||||
|
return nil, nil, NewArgError("id", "cannot be less than 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
if request == nil {
|
||||||
|
return nil, nil, NewArgError("request", "request can't be nil")
|
||||||
|
}
|
||||||
|
|
||||||
path := dropletActionPath(id)
|
path := dropletActionPath(id)
|
||||||
|
|
||||||
req, err := s.client.NewRequest("POST", path, request)
|
req, err := s.client.NewRequest("POST", path, request)
|
||||||
|
|
@ -119,6 +194,14 @@ func (s *DropletActionsServiceOp) doAction(id int, request *ActionRequest) (*Act
|
||||||
|
|
||||||
// Get an action for a particular droplet by id.
|
// Get an action for a particular droplet by id.
|
||||||
func (s *DropletActionsServiceOp) Get(dropletID, actionID int) (*Action, *Response, error) {
|
func (s *DropletActionsServiceOp) Get(dropletID, actionID int) (*Action, *Response, error) {
|
||||||
|
if dropletID < 1 {
|
||||||
|
return nil, nil, NewArgError("dropletID", "cannot be less than 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
if actionID < 1 {
|
||||||
|
return nil, nil, NewArgError("actionID", "cannot be less than 1")
|
||||||
|
}
|
||||||
|
|
||||||
path := fmt.Sprintf("%s/%d", dropletActionPath(dropletID), actionID)
|
path := fmt.Sprintf("%s/%d", dropletActionPath(dropletID), actionID)
|
||||||
return s.get(path)
|
return s.get(path)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,25 @@
|
||||||
package godo
|
package godo
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
const dropletBasePath = "v2/droplets"
|
const dropletBasePath = "v2/droplets"
|
||||||
|
|
||||||
// DropletsService is an interface for interfacing with the droplet
|
// DropletsService is an interface for interfacing with the droplet
|
||||||
// endpoints of the Digital Ocean API
|
// endpoints of the DigitalOcean API
|
||||||
// See: https://developers.digitalocean.com/#droplets
|
// See: https://developers.digitalocean.com/documentation/v2#droplets
|
||||||
type DropletsService interface {
|
type DropletsService interface {
|
||||||
List(*ListOptions) ([]Droplet, *Response, error)
|
List(*ListOptions) ([]Droplet, *Response, error)
|
||||||
Get(int) (*DropletRoot, *Response, error)
|
Get(int) (*Droplet, *Response, error)
|
||||||
Create(*DropletCreateRequest) (*DropletRoot, *Response, error)
|
Create(*DropletCreateRequest) (*Droplet, *Response, error)
|
||||||
Delete(int) (*Response, error)
|
Delete(int) (*Response, error)
|
||||||
dropletActionStatus(string) (string, 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DropletsServiceOp handles communication with the droplet related methods of the
|
// DropletsServiceOp handles communication with the droplet related methods of the
|
||||||
|
|
@ -21,6 +28,8 @@ type DropletsServiceOp struct {
|
||||||
client *Client
|
client *Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ DropletsService = &DropletsServiceOp{}
|
||||||
|
|
||||||
// Droplet represents a DigitalOcean Droplet
|
// Droplet represents a DigitalOcean Droplet
|
||||||
type Droplet struct {
|
type Droplet struct {
|
||||||
ID int `json:"id,float64,omitempty"`
|
ID int `json:"id,float64,omitempty"`
|
||||||
|
|
@ -31,12 +40,21 @@ type Droplet struct {
|
||||||
Region *Region `json:"region,omitempty"`
|
Region *Region `json:"region,omitempty"`
|
||||||
Image *Image `json:"image,omitempty"`
|
Image *Image `json:"image,omitempty"`
|
||||||
Size *Size `json:"size,omitempty"`
|
Size *Size `json:"size,omitempty"`
|
||||||
|
SizeSlug string `json:"size_slug,omitempty"`
|
||||||
BackupIDs []int `json:"backup_ids,omitempty"`
|
BackupIDs []int `json:"backup_ids,omitempty"`
|
||||||
SnapshotIDs []int `json:"snapshot_ids,omitempty"`
|
SnapshotIDs []int `json:"snapshot_ids,omitempty"`
|
||||||
Locked bool `json:"locked,bool,omitempty"`
|
Locked bool `json:"locked,bool,omitempty"`
|
||||||
Status string `json:"status,omitempty"`
|
Status string `json:"status,omitempty"`
|
||||||
Networks *Networks `json:"networks,omitempty"`
|
Networks *Networks `json:"networks,omitempty"`
|
||||||
ActionIDs []int `json:"action_ids,omitempty"`
|
ActionIDs []int `json:"action_ids,omitempty"`
|
||||||
|
Created string `json:"created_at,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kernel object
|
||||||
|
type Kernel struct {
|
||||||
|
ID int `json:"id,float64,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Version string `json:"version,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert Droplet to a string
|
// Convert Droplet to a string
|
||||||
|
|
@ -45,7 +63,7 @@ func (d Droplet) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DropletRoot represents a Droplet root
|
// DropletRoot represents a Droplet root
|
||||||
type DropletRoot struct {
|
type dropletRoot struct {
|
||||||
Droplet *Droplet `json:"droplet"`
|
Droplet *Droplet `json:"droplet"`
|
||||||
Links *Links `json:"links,omitempty"`
|
Links *Links `json:"links,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
@ -55,17 +73,64 @@ type dropletsRoot struct {
|
||||||
Links *Links `json:"links"`
|
Links *Links `json:"links"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type kernelsRoot struct {
|
||||||
|
Kernels []Kernel `json:"kernels,omitempty"`
|
||||||
|
Links *Links `json:"links"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type snapshotsRoot struct {
|
||||||
|
Snapshots []Image `json:"snapshots,omitempty"`
|
||||||
|
Links *Links `json:"links"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type backupsRoot struct {
|
||||||
|
Backups []Image `json:"backups,omitempty"`
|
||||||
|
Links *Links `json:"links"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DropletCreateImage identifies an image for the create request. It prefers slug over ID.
|
||||||
|
type DropletCreateImage struct {
|
||||||
|
ID int
|
||||||
|
Slug string
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON returns either the slug or id of the image. It returns the id
|
||||||
|
// if the slug is empty.
|
||||||
|
func (d DropletCreateImage) MarshalJSON() ([]byte, error) {
|
||||||
|
if d.Slug != "" {
|
||||||
|
return json.Marshal(d.Slug)
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(d.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DropletCreateSSHKey identifies a SSH Key for the create request. It prefers fingerprint over ID.
|
||||||
|
type DropletCreateSSHKey struct {
|
||||||
|
ID int
|
||||||
|
Fingerprint string
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON returns either the fingerprint or id of the ssh key. It returns
|
||||||
|
// the id if the fingerprint is empty.
|
||||||
|
func (d DropletCreateSSHKey) MarshalJSON() ([]byte, error) {
|
||||||
|
if d.Fingerprint != "" {
|
||||||
|
return json.Marshal(d.Fingerprint)
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(d.ID)
|
||||||
|
}
|
||||||
|
|
||||||
// DropletCreateRequest represents a request to create a droplet.
|
// DropletCreateRequest represents a request to create a droplet.
|
||||||
type DropletCreateRequest struct {
|
type DropletCreateRequest struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
Size string `json:"size"`
|
Size string `json:"size"`
|
||||||
Image string `json:"image"`
|
Image DropletCreateImage `json:"image"`
|
||||||
SSHKeys []interface{} `json:"ssh_keys"`
|
SSHKeys []DropletCreateSSHKey `json:"ssh_keys"`
|
||||||
Backups bool `json:"backups"`
|
Backups bool `json:"backups"`
|
||||||
IPv6 bool `json:"ipv6"`
|
IPv6 bool `json:"ipv6"`
|
||||||
PrivateNetworking bool `json:"private_networking"`
|
PrivateNetworking bool `json:"private_networking"`
|
||||||
UserData string `json:"user_data"`
|
UserData string `json:"user_data,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d DropletCreateRequest) String() string {
|
func (d DropletCreateRequest) String() string {
|
||||||
|
|
@ -74,19 +139,31 @@ func (d DropletCreateRequest) String() string {
|
||||||
|
|
||||||
// Networks represents the droplet's networks
|
// Networks represents the droplet's networks
|
||||||
type Networks struct {
|
type Networks struct {
|
||||||
V4 []Network `json:"v4,omitempty"`
|
V4 []NetworkV4 `json:"v4,omitempty"`
|
||||||
V6 []Network `json:"v6,omitempty"`
|
V6 []NetworkV6 `json:"v6,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Network represents a DigitalOcean Network
|
// NetworkV4 represents a DigitalOcean IPv4 Network
|
||||||
type Network struct {
|
type NetworkV4 struct {
|
||||||
IPAddress string `json:"ip_address,omitempty"`
|
IPAddress string `json:"ip_address,omitempty"`
|
||||||
Netmask string `json:"netmask,omitempty"`
|
Netmask string `json:"netmask,omitempty"`
|
||||||
Gateway string `json:"gateway,omitempty"`
|
Gateway string `json:"gateway,omitempty"`
|
||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n Network) String() string {
|
func (n NetworkV4) String() string {
|
||||||
|
return Stringify(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkV6 represents a DigitalOcean IPv6 network.
|
||||||
|
type NetworkV6 struct {
|
||||||
|
IPAddress string `json:"ip_address,omitempty"`
|
||||||
|
Netmask int `json:"netmask,omitempty"`
|
||||||
|
Gateway string `json:"gateway,omitempty"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n NetworkV6) String() string {
|
||||||
return Stringify(n)
|
return Stringify(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,7 +193,11 @@ func (s *DropletsServiceOp) List(opt *ListOptions) ([]Droplet, *Response, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get individual droplet
|
// Get individual droplet
|
||||||
func (s *DropletsServiceOp) Get(dropletID int) (*DropletRoot, *Response, error) {
|
func (s *DropletsServiceOp) Get(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)
|
path := fmt.Sprintf("%s/%d", dropletBasePath, dropletID)
|
||||||
|
|
||||||
req, err := s.client.NewRequest("GET", path, nil)
|
req, err := s.client.NewRequest("GET", path, nil)
|
||||||
|
|
@ -124,17 +205,21 @@ func (s *DropletsServiceOp) Get(dropletID int) (*DropletRoot, *Response, error)
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
root := new(DropletRoot)
|
root := new(dropletRoot)
|
||||||
resp, err := s.client.Do(req, root)
|
resp, err := s.client.Do(req, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, resp, err
|
return nil, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return root, resp, err
|
return root.Droplet, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create droplet
|
// Create droplet
|
||||||
func (s *DropletsServiceOp) Create(createRequest *DropletCreateRequest) (*DropletRoot, *Response, error) {
|
func (s *DropletsServiceOp) Create(createRequest *DropletCreateRequest) (*Droplet, *Response, error) {
|
||||||
|
if createRequest == nil {
|
||||||
|
return nil, nil, NewArgError("createRequest", "cannot be nil")
|
||||||
|
}
|
||||||
|
|
||||||
path := dropletBasePath
|
path := dropletBasePath
|
||||||
|
|
||||||
req, err := s.client.NewRequest("POST", path, createRequest)
|
req, err := s.client.NewRequest("POST", path, createRequest)
|
||||||
|
|
@ -142,7 +227,7 @@ func (s *DropletsServiceOp) Create(createRequest *DropletCreateRequest) (*Drople
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
root := new(DropletRoot)
|
root := new(dropletRoot)
|
||||||
resp, err := s.client.Do(req, root)
|
resp, err := s.client.Do(req, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, resp, err
|
return nil, resp, err
|
||||||
|
|
@ -151,11 +236,15 @@ func (s *DropletsServiceOp) Create(createRequest *DropletCreateRequest) (*Drople
|
||||||
resp.Links = l
|
resp.Links = l
|
||||||
}
|
}
|
||||||
|
|
||||||
return root, resp, err
|
return root.Droplet, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete droplet
|
// Delete droplet
|
||||||
func (s *DropletsServiceOp) Delete(dropletID int) (*Response, error) {
|
func (s *DropletsServiceOp) Delete(dropletID int) (*Response, error) {
|
||||||
|
if dropletID < 1 {
|
||||||
|
return nil, NewArgError("dropletID", "cannot be less than 1")
|
||||||
|
}
|
||||||
|
|
||||||
path := fmt.Sprintf("%s/%d", dropletBasePath, dropletID)
|
path := fmt.Sprintf("%s/%d", dropletBasePath, dropletID)
|
||||||
|
|
||||||
req, err := s.client.NewRequest("DELETE", path, nil)
|
req, err := s.client.NewRequest("DELETE", path, nil)
|
||||||
|
|
@ -168,6 +257,141 @@ func (s *DropletsServiceOp) Delete(dropletID int) (*Response, error) {
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Kernels lists kernels available for a droplet.
|
||||||
|
func (s *DropletsServiceOp) Kernels(dropletID int, opt *ListOptions) ([]Kernel, *Response, error) {
|
||||||
|
if dropletID < 1 {
|
||||||
|
return nil, nil, NewArgError("dropletID", "cannot be less than 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
path := fmt.Sprintf("%s/%d/kernels", dropletBasePath, dropletID)
|
||||||
|
path, err := addOptions(path, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
root := new(kernelsRoot)
|
||||||
|
resp, err := s.client.Do(req, root)
|
||||||
|
if l := root.Links; l != nil {
|
||||||
|
resp.Links = l
|
||||||
|
}
|
||||||
|
|
||||||
|
return root.Kernels, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actions lists the actions for a droplet.
|
||||||
|
func (s *DropletsServiceOp) Actions(dropletID int, opt *ListOptions) ([]Action, *Response, error) {
|
||||||
|
if dropletID < 1 {
|
||||||
|
return nil, nil, NewArgError("dropletID", "cannot be less than 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
path := fmt.Sprintf("%s/%d/actions", dropletBasePath, dropletID)
|
||||||
|
path, err := addOptions(path, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
root := new(actionsRoot)
|
||||||
|
resp, err := s.client.Do(req, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
if l := root.Links; l != nil {
|
||||||
|
resp.Links = l
|
||||||
|
}
|
||||||
|
|
||||||
|
return root.Actions, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backups lists the backups for a droplet.
|
||||||
|
func (s *DropletsServiceOp) Backups(dropletID int, opt *ListOptions) ([]Image, *Response, error) {
|
||||||
|
if dropletID < 1 {
|
||||||
|
return nil, nil, NewArgError("dropletID", "cannot be less than 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
path := fmt.Sprintf("%s/%d/backups", dropletBasePath, dropletID)
|
||||||
|
path, err := addOptions(path, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
root := new(backupsRoot)
|
||||||
|
resp, err := s.client.Do(req, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
if l := root.Links; l != nil {
|
||||||
|
resp.Links = l
|
||||||
|
}
|
||||||
|
|
||||||
|
return root.Backups, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Snapshots lists the snapshots available for a droplet.
|
||||||
|
func (s *DropletsServiceOp) Snapshots(dropletID int, opt *ListOptions) ([]Image, *Response, error) {
|
||||||
|
if dropletID < 1 {
|
||||||
|
return nil, nil, NewArgError("dropletID", "cannot be less than 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
path := fmt.Sprintf("%s/%d/snapshots", dropletBasePath, dropletID)
|
||||||
|
path, err := addOptions(path, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
root := new(snapshotsRoot)
|
||||||
|
resp, err := s.client.Do(req, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
if l := root.Links; l != nil {
|
||||||
|
resp.Links = l
|
||||||
|
}
|
||||||
|
|
||||||
|
return root.Snapshots, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Neighbors lists the neighbors for a droplet.
|
||||||
|
func (s *DropletsServiceOp) Neighbors(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)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
root := new(dropletsRoot)
|
||||||
|
resp, err := s.client.Do(req, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return root.Droplets, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *DropletsServiceOp) dropletActionStatus(uri string) (string, error) {
|
func (s *DropletsServiceOp) dropletActionStatus(uri string) (string, error) {
|
||||||
action, _, err := s.client.DropletActions.GetByURI(uri)
|
action, _, err := s.client.DropletActions.GetByURI(uri)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package godo
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// ArgError is an error that represents an error with an input to godo. It
|
||||||
|
// identifies the argument and the cause (if possible).
|
||||||
|
type ArgError struct {
|
||||||
|
arg string
|
||||||
|
reason string
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ error = &ArgError{}
|
||||||
|
|
||||||
|
// NewArgError creates an InputError.
|
||||||
|
func NewArgError(arg, reason string) *ArgError {
|
||||||
|
return &ArgError{
|
||||||
|
arg: arg,
|
||||||
|
reason: reason,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ArgError) Error() string {
|
||||||
|
return fmt.Sprintf("%s is invalid because %s", e.arg, e.reason)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
package godo
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
const floatingBasePath = "v2/floating_ips"
|
||||||
|
|
||||||
|
// FloatingIPsService is an interface for interfacing with the 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FloatingIPsServiceOp handles communication with the floating IPs related methods of the
|
||||||
|
// DigitalOcean API.
|
||||||
|
type FloatingIPsServiceOp struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ FloatingIPsService = &FloatingIPsServiceOp{}
|
||||||
|
|
||||||
|
// FloatingIP represents a Digital Ocean floating IP.
|
||||||
|
type FloatingIP struct {
|
||||||
|
Region *Region `json:"region"`
|
||||||
|
Droplet *Droplet `json:"droplet"`
|
||||||
|
IP string `json:"ip"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f FloatingIP) String() string {
|
||||||
|
return Stringify(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
type floatingIPsRoot struct {
|
||||||
|
FloatingIPs []FloatingIP `json:"floating_ips"`
|
||||||
|
Links *Links `json:"links"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type floatingIPRoot struct {
|
||||||
|
FloatingIP *FloatingIP `json:"floating_ip"`
|
||||||
|
Links *Links `json:"links,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FloatingIPCreateRequest represents a request to create a floating IP.
|
||||||
|
// If DropletID is not empty, the floating IP will be assigned to the
|
||||||
|
// droplet.
|
||||||
|
type FloatingIPCreateRequest struct {
|
||||||
|
Region string `json:"region"`
|
||||||
|
DropletID int `json:"droplet_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// List all floating IPs.
|
||||||
|
func (f *FloatingIPsServiceOp) List(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)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
root := new(floatingIPsRoot)
|
||||||
|
resp, err := f.client.Do(req, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
if l := root.Links; l != nil {
|
||||||
|
resp.Links = l
|
||||||
|
}
|
||||||
|
|
||||||
|
return root.FloatingIPs, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get an individual floating IP.
|
||||||
|
func (f *FloatingIPsServiceOp) Get(ip string) (*FloatingIP, *Response, error) {
|
||||||
|
path := fmt.Sprintf("%s/%s", floatingBasePath, ip)
|
||||||
|
|
||||||
|
req, err := f.client.NewRequest("GET", path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
root := new(floatingIPRoot)
|
||||||
|
resp, err := f.client.Do(req, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return root.FloatingIP, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
path := floatingBasePath
|
||||||
|
|
||||||
|
req, err := f.client.NewRequest("POST", path, createRequest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
root := new(floatingIPRoot)
|
||||||
|
resp, err := f.client.Do(req, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
if l := root.Links; l != nil {
|
||||||
|
resp.Links = l
|
||||||
|
}
|
||||||
|
|
||||||
|
return root.FloatingIP, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete a floating IP.
|
||||||
|
func (f *FloatingIPsServiceOp) Delete(ip string) (*Response, error) {
|
||||||
|
path := fmt.Sprintf("%s/%s", floatingBasePath, ip)
|
||||||
|
|
||||||
|
req, err := f.client.NewRequest("DELETE", path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := f.client.Do(req, nil)
|
||||||
|
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
package godo
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// 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) ([]Action, *Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FloatingIPActionsServiceOp handles communication with the floating IPs
|
||||||
|
// action related methods of the DigitalOcean API.
|
||||||
|
type FloatingIPActionsServiceOp struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign a floating IP to a droplet.
|
||||||
|
func (s *FloatingIPActionsServiceOp) Assign(ip string, dropletID int) (*Action, *Response, error) {
|
||||||
|
request := &ActionRequest{
|
||||||
|
"type": "assign",
|
||||||
|
"droplet_id": dropletID,
|
||||||
|
}
|
||||||
|
return s.doAction(ip, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unassign a floating IP from the droplet it is currently assigned to.
|
||||||
|
func (s *FloatingIPActionsServiceOp) Unassign(ip string) (*Action, *Response, error) {
|
||||||
|
request := &ActionRequest{"type": "unassign"}
|
||||||
|
return s.doAction(ip, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get an action for a particular floating IP by id.
|
||||||
|
func (s *FloatingIPActionsServiceOp) Get(ip string, actionID int) (*Action, *Response, error) {
|
||||||
|
path := fmt.Sprintf("%s/%d", floatingIPActionPath(ip), actionID)
|
||||||
|
return s.get(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List the actions for a particular floating IP.
|
||||||
|
func (s *FloatingIPActionsServiceOp) List(ip string) ([]Action, *Response, error) {
|
||||||
|
path := floatingIPActionPath(ip)
|
||||||
|
return s.list(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FloatingIPActionsServiceOp) doAction(ip string, request *ActionRequest) (*Action, *Response, error) {
|
||||||
|
path := floatingIPActionPath(ip)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("POST", path, request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
root := new(actionRoot)
|
||||||
|
resp, err := s.client.Do(req, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &root.Event, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FloatingIPActionsServiceOp) get(path string) (*Action, *Response, error) {
|
||||||
|
req, err := s.client.NewRequest("GET", path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
root := new(actionRoot)
|
||||||
|
resp, err := s.client.Do(req, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &root.Event, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FloatingIPActionsServiceOp) list(path string) ([]Action, *Response, error) {
|
||||||
|
req, err := s.client.NewRequest("GET", path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
root := new(actionsRoot)
|
||||||
|
resp, err := s.client.Do(req, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return root.Actions, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func floatingIPActionPath(ip string) string {
|
||||||
|
return fmt.Sprintf("%s/%s/actions", floatingBasePath, ip)
|
||||||
|
}
|
||||||
|
|
@ -43,17 +43,26 @@ type Client struct {
|
||||||
Rate Rate
|
Rate Rate
|
||||||
|
|
||||||
// Services used for communicating with the API
|
// Services used for communicating with the API
|
||||||
Actions ActionsService
|
Account AccountService
|
||||||
Domains DomainsService
|
Actions ActionsService
|
||||||
Droplets DropletsService
|
Domains DomainsService
|
||||||
DropletActions DropletActionsService
|
Droplets DropletsService
|
||||||
Images ImagesService
|
DropletActions DropletActionsService
|
||||||
ImageActions ImageActionsService
|
Images ImagesService
|
||||||
Keys KeysService
|
ImageActions ImageActionsService
|
||||||
Regions RegionsService
|
Keys KeysService
|
||||||
Sizes SizesService
|
Regions RegionsService
|
||||||
|
Sizes SizesService
|
||||||
|
FloatingIPs FloatingIPsService
|
||||||
|
FloatingIPActions FloatingIPActionsService
|
||||||
|
|
||||||
|
// Optional function called after every successful request made to the DO APIs
|
||||||
|
onRequestCompleted RequestCompletionCallback
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RequestCompletionCallback defines the type of the request callback function
|
||||||
|
type RequestCompletionCallback func(*http.Request, *http.Response)
|
||||||
|
|
||||||
// ListOptions specifies the optional parameters to various List methods that
|
// ListOptions specifies the optional parameters to various List methods that
|
||||||
// support pagination.
|
// support pagination.
|
||||||
type ListOptions struct {
|
type ListOptions struct {
|
||||||
|
|
@ -64,7 +73,7 @@ type ListOptions struct {
|
||||||
PerPage int `url:"per_page,omitempty"`
|
PerPage int `url:"per_page,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Response is a Digital Ocean response. This wraps the standard http.Response returned from DigitalOcean.
|
// Response is a DigitalOcean response. This wraps the standard http.Response returned from DigitalOcean.
|
||||||
type Response struct {
|
type Response struct {
|
||||||
*http.Response
|
*http.Response
|
||||||
|
|
||||||
|
|
@ -106,21 +115,27 @@ func addOptions(s string, opt interface{}) (string, error) {
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
u, err := url.Parse(s)
|
origURL, err := url.Parse(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return s, err
|
return s, err
|
||||||
}
|
}
|
||||||
|
|
||||||
qv, err := query.Values(opt)
|
origValues := origURL.Query()
|
||||||
|
|
||||||
|
newValues, err := query.Values(opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return s, err
|
return s, err
|
||||||
}
|
}
|
||||||
|
|
||||||
u.RawQuery = qv.Encode()
|
for k, v := range newValues {
|
||||||
return u.String(), nil
|
origValues[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
origURL.RawQuery = origValues.Encode()
|
||||||
|
return origURL.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient returns a new Digital Ocean API client.
|
// NewClient returns a new DigitalOcean API client.
|
||||||
func NewClient(httpClient *http.Client) *Client {
|
func NewClient(httpClient *http.Client) *Client {
|
||||||
if httpClient == nil {
|
if httpClient == nil {
|
||||||
httpClient = http.DefaultClient
|
httpClient = http.DefaultClient
|
||||||
|
|
@ -129,6 +144,7 @@ func NewClient(httpClient *http.Client) *Client {
|
||||||
baseURL, _ := url.Parse(defaultBaseURL)
|
baseURL, _ := url.Parse(defaultBaseURL)
|
||||||
|
|
||||||
c := &Client{client: httpClient, BaseURL: baseURL, UserAgent: userAgent}
|
c := &Client{client: httpClient, BaseURL: baseURL, UserAgent: userAgent}
|
||||||
|
c.Account = &AccountServiceOp{client: c}
|
||||||
c.Actions = &ActionsServiceOp{client: c}
|
c.Actions = &ActionsServiceOp{client: c}
|
||||||
c.Domains = &DomainsServiceOp{client: c}
|
c.Domains = &DomainsServiceOp{client: c}
|
||||||
c.Droplets = &DropletsServiceOp{client: c}
|
c.Droplets = &DropletsServiceOp{client: c}
|
||||||
|
|
@ -138,6 +154,8 @@ func NewClient(httpClient *http.Client) *Client {
|
||||||
c.Keys = &KeysServiceOp{client: c}
|
c.Keys = &KeysServiceOp{client: c}
|
||||||
c.Regions = &RegionsServiceOp{client: c}
|
c.Regions = &RegionsServiceOp{client: c}
|
||||||
c.Sizes = &SizesServiceOp{client: c}
|
c.Sizes = &SizesServiceOp{client: c}
|
||||||
|
c.FloatingIPs = &FloatingIPsServiceOp{client: c}
|
||||||
|
c.FloatingIPActions = &FloatingIPActionsServiceOp{client: c}
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
@ -172,6 +190,11 @@ func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Requ
|
||||||
return req, nil
|
return req, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnRequestCompleted sets the DO API request completion callback
|
||||||
|
func (c *Client) OnRequestCompleted(rc RequestCompletionCallback) {
|
||||||
|
c.onRequestCompleted = rc
|
||||||
|
}
|
||||||
|
|
||||||
// newResponse creates a new Response for the provided http.Response
|
// newResponse creates a new Response for the provided http.Response
|
||||||
func newResponse(r *http.Response) *Response {
|
func newResponse(r *http.Response) *Response {
|
||||||
response := Response{Response: r}
|
response := Response{Response: r}
|
||||||
|
|
@ -222,8 +245,15 @@ func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if c.onRequestCompleted != nil {
|
||||||
|
c.onRequestCompleted(req, resp)
|
||||||
|
}
|
||||||
|
|
||||||
defer resp.Body.Close()
|
defer func() {
|
||||||
|
if rerr := resp.Body.Close(); err == nil {
|
||||||
|
err = rerr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
response := newResponse(resp)
|
response := newResponse(resp)
|
||||||
c.Rate = response.Rate
|
c.Rate = response.Rate
|
||||||
|
|
@ -235,9 +265,15 @@ func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
|
||||||
|
|
||||||
if v != nil {
|
if v != nil {
|
||||||
if w, ok := v.(io.Writer); ok {
|
if w, ok := v.(io.Writer); ok {
|
||||||
io.Copy(w, resp.Body)
|
_, err := io.Copy(w, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
json.NewDecoder(resp.Body).Decode(v)
|
err := json.NewDecoder(resp.Body).Decode(v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -259,7 +295,10 @@ func CheckResponse(r *http.Response) error {
|
||||||
errorResponse := &ErrorResponse{Response: r}
|
errorResponse := &ErrorResponse{Response: r}
|
||||||
data, err := ioutil.ReadAll(r.Body)
|
data, err := ioutil.ReadAll(r.Body)
|
||||||
if err == nil && len(data) > 0 {
|
if err == nil && len(data) > 0 {
|
||||||
json.Unmarshal(data, errorResponse)
|
err := json.Unmarshal(data, errorResponse)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return errorResponse
|
return errorResponse
|
||||||
|
|
@ -297,6 +336,6 @@ func Bool(v bool) *bool {
|
||||||
// StreamToString converts a reader to a string
|
// StreamToString converts a reader to a string
|
||||||
func StreamToString(stream io.Reader) string {
|
func StreamToString(stream io.Reader) string {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
buf.ReadFrom(stream)
|
_, _ = buf.ReadFrom(stream)
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ package godo
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
// ImageActionsService is an interface for interfacing with the image actions
|
// ImageActionsService is an interface for interfacing with the image actions
|
||||||
// endpoints of the Digital Ocean API
|
// endpoints of the DigitalOcean API
|
||||||
// See: https://developers.digitalocean.com/#image-actions
|
// See: https://developers.digitalocean.com/documentation/v2#image-actions
|
||||||
type ImageActionsService interface {
|
type ImageActionsService interface {
|
||||||
Get(int, int) (*Action, *Response, error)
|
Get(int, int) (*Action, *Response, error)
|
||||||
Transfer(int, *ActionRequest) (*Action, *Response, error)
|
Transfer(int, *ActionRequest) (*Action, *Response, error)
|
||||||
|
|
@ -16,8 +16,18 @@ type ImageActionsServiceOp struct {
|
||||||
client *Client
|
client *Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ ImageActionsService = &ImageActionsServiceOp{}
|
||||||
|
|
||||||
// Transfer an image
|
// Transfer an image
|
||||||
func (i *ImageActionsServiceOp) Transfer(imageID int, transferRequest *ActionRequest) (*Action, *Response, error) {
|
func (i *ImageActionsServiceOp) Transfer(imageID int, transferRequest *ActionRequest) (*Action, *Response, error) {
|
||||||
|
if imageID < 1 {
|
||||||
|
return nil, nil, NewArgError("imageID", "cannot be less than 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
if transferRequest == nil {
|
||||||
|
return nil, nil, NewArgError("transferRequest", "cannot be nil")
|
||||||
|
}
|
||||||
|
|
||||||
path := fmt.Sprintf("v2/images/%d/actions", imageID)
|
path := fmt.Sprintf("v2/images/%d/actions", imageID)
|
||||||
|
|
||||||
req, err := i.client.NewRequest("POST", path, transferRequest)
|
req, err := i.client.NewRequest("POST", path, transferRequest)
|
||||||
|
|
@ -36,6 +46,14 @@ func (i *ImageActionsServiceOp) Transfer(imageID int, transferRequest *ActionReq
|
||||||
|
|
||||||
// Get an action for a particular image by id.
|
// Get an action for a particular image by id.
|
||||||
func (i *ImageActionsServiceOp) Get(imageID, actionID int) (*Action, *Response, error) {
|
func (i *ImageActionsServiceOp) Get(imageID, actionID int) (*Action, *Response, error) {
|
||||||
|
if imageID < 1 {
|
||||||
|
return nil, nil, NewArgError("imageID", "cannot be less than 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
if actionID < 1 {
|
||||||
|
return nil, nil, NewArgError("actionID", "cannot be less than 1")
|
||||||
|
}
|
||||||
|
|
||||||
path := fmt.Sprintf("v2/images/%d/actions/%d", imageID, actionID)
|
path := fmt.Sprintf("v2/images/%d/actions/%d", imageID, actionID)
|
||||||
|
|
||||||
req, err := i.client.NewRequest("GET", path, nil)
|
req, err := i.client.NewRequest("GET", path, nil)
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,21 @@
|
||||||
package godo
|
package godo
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
const imageBasePath = "v2/images"
|
||||||
|
|
||||||
// ImagesService is an interface for interfacing with the images
|
// ImagesService is an interface for interfacing with the images
|
||||||
// endpoints of the Digital Ocean API
|
// endpoints of the DigitalOcean API
|
||||||
// See: https://developers.digitalocean.com/#images
|
// See: https://developers.digitalocean.com/documentation/v2#images
|
||||||
type ImagesService interface {
|
type ImagesService interface {
|
||||||
List(*ListOptions) ([]Image, *Response, error)
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImagesServiceOp handles communication with the image related methods of the
|
// ImagesServiceOp handles communication with the image related methods of the
|
||||||
|
|
@ -13,14 +24,24 @@ type ImagesServiceOp struct {
|
||||||
client *Client
|
client *Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ ImagesService = &ImagesServiceOp{}
|
||||||
|
|
||||||
// Image represents a DigitalOcean Image
|
// Image represents a DigitalOcean Image
|
||||||
type Image struct {
|
type Image struct {
|
||||||
ID int `json:"id,float64,omitempty"`
|
ID int `json:"id,float64,omitempty"`
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
Distribution string `json:"distribution,omitempty"`
|
Distribution string `json:"distribution,omitempty"`
|
||||||
Slug string `json:"slug,omitempty"`
|
Slug string `json:"slug,omitempty"`
|
||||||
Public bool `json:"public,omitempty"`
|
Public bool `json:"public,omitempty"`
|
||||||
Regions []string `json:"regions,omitempty"`
|
Regions []string `json:"regions,omitempty"`
|
||||||
|
MinDiskSize int `json:"min_disk_size,omitempty"`
|
||||||
|
Created string `json:"created_at,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImageUpdateRequest represents a request to update an image.
|
||||||
|
type ImageUpdateRequest struct {
|
||||||
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type imageRoot struct {
|
type imageRoot struct {
|
||||||
|
|
@ -32,17 +53,128 @@ type imagesRoot struct {
|
||||||
Links *Links `json:"links"`
|
Links *Links `json:"links"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type listImageOptions struct {
|
||||||
|
Private bool `url:"private,omitempty"`
|
||||||
|
Type string `url:"type,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
func (i Image) String() string {
|
func (i Image) String() string {
|
||||||
return Stringify(i)
|
return Stringify(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List all sizes
|
// List lists all the images available.
|
||||||
func (s *ImagesServiceOp) List(opt *ListOptions) ([]Image, *Response, error) {
|
func (s *ImagesServiceOp) List(opt *ListOptions) ([]Image, *Response, error) {
|
||||||
path := "v2/images"
|
return s.list(opt, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListDistribution lists all the distribution images.
|
||||||
|
func (s *ImagesServiceOp) ListDistribution(opt *ListOptions) ([]Image, *Response, error) {
|
||||||
|
listOpt := listImageOptions{Type: "distribution"}
|
||||||
|
return s.list(opt, &listOpt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListApplication lists all the application images.
|
||||||
|
func (s *ImagesServiceOp) ListApplication(opt *ListOptions) ([]Image, *Response, error) {
|
||||||
|
listOpt := listImageOptions{Type: "application"}
|
||||||
|
return s.list(opt, &listOpt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListUser lists all the user images.
|
||||||
|
func (s *ImagesServiceOp) ListUser(opt *ListOptions) ([]Image, *Response, error) {
|
||||||
|
listOpt := listImageOptions{Private: true}
|
||||||
|
return s.list(opt, &listOpt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByID retrieves an image by id.
|
||||||
|
func (s *ImagesServiceOp) GetByID(imageID int) (*Image, *Response, error) {
|
||||||
|
if imageID < 1 {
|
||||||
|
return nil, nil, NewArgError("imageID", "cannot be less than 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.get(interface{}(imageID))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBySlug retrieves an image by slug.
|
||||||
|
func (s *ImagesServiceOp) GetBySlug(slug string) (*Image, *Response, error) {
|
||||||
|
if len(slug) < 1 {
|
||||||
|
return nil, nil, NewArgError("slug", "cannot be blank")
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.get(interface{}(slug))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update an image name.
|
||||||
|
func (s *ImagesServiceOp) Update(imageID int, updateRequest *ImageUpdateRequest) (*Image, *Response, error) {
|
||||||
|
if imageID < 1 {
|
||||||
|
return nil, nil, NewArgError("imageID", "cannot be less than 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
if updateRequest == nil {
|
||||||
|
return nil, nil, NewArgError("updateRequest", "cannot be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
path := fmt.Sprintf("%s/%d", imageBasePath, imageID)
|
||||||
|
req, err := s.client.NewRequest("PUT", path, updateRequest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
root := new(imageRoot)
|
||||||
|
resp, err := s.client.Do(req, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &root.Image, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete an image.
|
||||||
|
func (s *ImagesServiceOp) Delete(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)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := s.client.Do(req, nil)
|
||||||
|
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method for getting an individual image
|
||||||
|
func (s *ImagesServiceOp) get(ID interface{}) (*Image, *Response, error) {
|
||||||
|
path := fmt.Sprintf("%s/%v", imageBasePath, ID)
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
root := new(imageRoot)
|
||||||
|
resp, err := s.client.Do(req, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &root.Image, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method for listing images
|
||||||
|
func (s *ImagesServiceOp) list(opt *ListOptions, listOpt *listImageOptions) ([]Image, *Response, error) {
|
||||||
|
path := imageBasePath
|
||||||
path, err := addOptions(path, opt)
|
path, err := addOptions(path, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
path, err = addOptions(path, listOpt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
req, err := s.client.NewRequest("GET", path, nil)
|
req, err := s.client.NewRequest("GET", path, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@ import "fmt"
|
||||||
const keysBasePath = "v2/account/keys"
|
const keysBasePath = "v2/account/keys"
|
||||||
|
|
||||||
// KeysService is an interface for interfacing with the keys
|
// KeysService is an interface for interfacing with the keys
|
||||||
// endpoints of the Digital Ocean API
|
// endpoints of the DigitalOcean API
|
||||||
// See: https://developers.digitalocean.com/#keys
|
// See: https://developers.digitalocean.com/documentation/v2#keys
|
||||||
type KeysService interface {
|
type KeysService interface {
|
||||||
List(*ListOptions) ([]Key, *Response, error)
|
List(*ListOptions) ([]Key, *Response, error)
|
||||||
GetByID(int) (*Key, *Response, error)
|
GetByID(int) (*Key, *Response, error)
|
||||||
GetByFingerprint(string) (*Key, *Response, error)
|
GetByFingerprint(string) (*Key, *Response, error)
|
||||||
Create(*KeyCreateRequest) (*Key, *Response, error)
|
Create(*KeyCreateRequest) (*Key, *Response, error)
|
||||||
|
UpdateByID(int, *KeyUpdateRequest) (*Key, *Response, error)
|
||||||
|
UpdateByFingerprint(string, *KeyUpdateRequest) (*Key, *Response, error)
|
||||||
DeleteByID(int) (*Response, error)
|
DeleteByID(int) (*Response, error)
|
||||||
DeleteByFingerprint(string) (*Response, error)
|
DeleteByFingerprint(string) (*Response, error)
|
||||||
}
|
}
|
||||||
|
|
@ -22,6 +24,8 @@ type KeysServiceOp struct {
|
||||||
client *Client
|
client *Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ KeysService = &KeysServiceOp{}
|
||||||
|
|
||||||
// Key represents a DigitalOcean Key.
|
// Key represents a DigitalOcean Key.
|
||||||
type Key struct {
|
type Key struct {
|
||||||
ID int `json:"id,float64,omitempty"`
|
ID int `json:"id,float64,omitempty"`
|
||||||
|
|
@ -30,6 +34,11 @@ type Key struct {
|
||||||
PublicKey string `json:"public_key,omitempty"`
|
PublicKey string `json:"public_key,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KeyUpdateRequest represents a request to update a DigitalOcean key.
|
||||||
|
type KeyUpdateRequest struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
type keysRoot struct {
|
type keysRoot struct {
|
||||||
SSHKeys []Key `json:"ssh_keys"`
|
SSHKeys []Key `json:"ssh_keys"`
|
||||||
Links *Links `json:"links"`
|
Links *Links `json:"links"`
|
||||||
|
|
@ -92,18 +101,30 @@ func (s *KeysServiceOp) get(path string) (*Key, *Response, error) {
|
||||||
|
|
||||||
// GetByID gets a Key by id
|
// GetByID gets a Key by id
|
||||||
func (s *KeysServiceOp) GetByID(keyID int) (*Key, *Response, error) {
|
func (s *KeysServiceOp) GetByID(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)
|
path := fmt.Sprintf("%s/%d", keysBasePath, keyID)
|
||||||
return s.get(path)
|
return s.get(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetByFingerprint gets a Key by by fingerprint
|
// GetByFingerprint gets a Key by by fingerprint
|
||||||
func (s *KeysServiceOp) GetByFingerprint(fingerprint string) (*Key, *Response, error) {
|
func (s *KeysServiceOp) GetByFingerprint(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)
|
path := fmt.Sprintf("%s/%s", keysBasePath, fingerprint)
|
||||||
return s.get(path)
|
return s.get(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a key using a KeyCreateRequest
|
// Create a key using a KeyCreateRequest
|
||||||
func (s *KeysServiceOp) Create(createRequest *KeyCreateRequest) (*Key, *Response, error) {
|
func (s *KeysServiceOp) Create(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("POST", keysBasePath, createRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
|
@ -118,6 +139,56 @@ func (s *KeysServiceOp) Create(createRequest *KeyCreateRequest) (*Key, *Response
|
||||||
return &root.SSHKey, resp, err
|
return &root.SSHKey, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateByID updates a key name by ID.
|
||||||
|
func (s *KeysServiceOp) UpdateByID(keyID int, updateRequest *KeyUpdateRequest) (*Key, *Response, error) {
|
||||||
|
if keyID < 1 {
|
||||||
|
return nil, nil, NewArgError("keyID", "cannot be less than 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
if updateRequest == nil {
|
||||||
|
return nil, nil, NewArgError("updateRequest", "cannot be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
path := fmt.Sprintf("%s/%d", keysBasePath, keyID)
|
||||||
|
req, err := s.client.NewRequest("PUT", path, updateRequest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
root := new(keyRoot)
|
||||||
|
resp, err := s.client.Do(req, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &root.SSHKey, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateByFingerprint updates a key name by fingerprint.
|
||||||
|
func (s *KeysServiceOp) UpdateByFingerprint(fingerprint string, updateRequest *KeyUpdateRequest) (*Key, *Response, error) {
|
||||||
|
if len(fingerprint) < 1 {
|
||||||
|
return nil, nil, NewArgError("fingerprint", "cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
if updateRequest == nil {
|
||||||
|
return nil, nil, NewArgError("updateRequest", "cannot be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
path := fmt.Sprintf("%s/%s", keysBasePath, fingerprint)
|
||||||
|
req, err := s.client.NewRequest("PUT", path, updateRequest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
root := new(keyRoot)
|
||||||
|
resp, err := s.client.Do(req, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &root.SSHKey, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
// Delete key using a path
|
// Delete key using a path
|
||||||
func (s *KeysServiceOp) delete(path string) (*Response, error) {
|
func (s *KeysServiceOp) delete(path string) (*Response, error) {
|
||||||
req, err := s.client.NewRequest("DELETE", path, nil)
|
req, err := s.client.NewRequest("DELETE", path, nil)
|
||||||
|
|
@ -132,12 +203,20 @@ func (s *KeysServiceOp) delete(path string) (*Response, error) {
|
||||||
|
|
||||||
// DeleteByID deletes a key by its id
|
// DeleteByID deletes a key by its id
|
||||||
func (s *KeysServiceOp) DeleteByID(keyID int) (*Response, error) {
|
func (s *KeysServiceOp) DeleteByID(keyID int) (*Response, error) {
|
||||||
|
if keyID < 1 {
|
||||||
|
return nil, NewArgError("keyID", "cannot be less than 1")
|
||||||
|
}
|
||||||
|
|
||||||
path := fmt.Sprintf("%s/%d", keysBasePath, keyID)
|
path := fmt.Sprintf("%s/%d", keysBasePath, keyID)
|
||||||
return s.delete(path)
|
return s.delete(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteByFingerprint deletes a key by its fingerprint
|
// DeleteByFingerprint deletes a key by its fingerprint
|
||||||
func (s *KeysServiceOp) DeleteByFingerprint(fingerprint string) (*Response, error) {
|
func (s *KeysServiceOp) DeleteByFingerprint(fingerprint string) (*Response, error) {
|
||||||
|
if len(fingerprint) < 1 {
|
||||||
|
return nil, NewArgError("fingerprint", "cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
path := fmt.Sprintf("%s/%s", keysBasePath, fingerprint)
|
path := fmt.Sprintf("%s/%s", keysBasePath, fingerprint)
|
||||||
return s.delete(path)
|
return s.delete(path)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,7 @@ func pageForURL(urlText string) (int, error) {
|
||||||
return page, nil
|
return page, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get a link action by id.
|
||||||
func (la *LinkAction) Get(client *Client) (*Action, *Response, error) {
|
func (la *LinkAction) Get(client *Client) (*Action, *Response, error) {
|
||||||
return client.Actions.Get(la.ID)
|
return client.Actions.Get(la.ID)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
package godo
|
package godo
|
||||||
|
|
||||||
// RegionsService is an interface for interfacing with the regions
|
// RegionsService is an interface for interfacing with the regions
|
||||||
// endpoints of the Digital Ocean API
|
// endpoints of the DigitalOcean API
|
||||||
// See: https://developers.digitalocean.com/#regions
|
// See: https://developers.digitalocean.com/documentation/v2#regions
|
||||||
type RegionsService interface {
|
type RegionsService interface {
|
||||||
List(*ListOptions) ([]Region, *Response, error)
|
List(*ListOptions) ([]Region, *Response, error)
|
||||||
}
|
}
|
||||||
|
|
@ -13,13 +13,15 @@ type RegionsServiceOp struct {
|
||||||
client *Client
|
client *Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ RegionsService = &RegionsServiceOp{}
|
||||||
|
|
||||||
// Region represents a DigitalOcean Region
|
// Region represents a DigitalOcean Region
|
||||||
type Region struct {
|
type Region struct {
|
||||||
Slug string `json:"slug,omitempty"`
|
Slug string `json:"slug,omitempty"`
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Sizes []string `json:"sizes,omitempty"`
|
Sizes []string `json:"sizes,omitempty"`
|
||||||
Available bool `json:"available,omitempty`
|
Available bool `json:"available,omitempty"`
|
||||||
Features []string `json:"features,omitempty`
|
Features []string `json:"features,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type regionsRoot struct {
|
type regionsRoot struct {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
package godo
|
package godo
|
||||||
|
|
||||||
// SizesService is an interface for interfacing with the size
|
// SizesService is an interface for interfacing with the size
|
||||||
// endpoints of the Digital Ocean API
|
// endpoints of the DigitalOcean API
|
||||||
// See: https://developers.digitalocean.com/#sizes
|
// See: https://developers.digitalocean.com/documentation/v2#sizes
|
||||||
type SizesService interface {
|
type SizesService interface {
|
||||||
List(*ListOptions) ([]Size, *Response, error)
|
List(*ListOptions) ([]Size, *Response, error)
|
||||||
}
|
}
|
||||||
|
|
@ -13,6 +13,8 @@ type SizesServiceOp struct {
|
||||||
client *Client
|
client *Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ SizesService = &SizesServiceOp{}
|
||||||
|
|
||||||
// Size represents a DigitalOcean Size
|
// Size represents a DigitalOcean Size
|
||||||
type Size struct {
|
type Size struct {
|
||||||
Slug string `json:"slug,omitempty"`
|
Slug string `json:"slug,omitempty"`
|
||||||
|
|
@ -22,6 +24,8 @@ type Size struct {
|
||||||
PriceMonthly float64 `json:"price_monthly,omitempty"`
|
PriceMonthly float64 `json:"price_monthly,omitempty"`
|
||||||
PriceHourly float64 `json:"price_hourly,omitempty"`
|
PriceHourly float64 `json:"price_hourly,omitempty"`
|
||||||
Regions []string `json:"regions,omitempty"`
|
Regions []string `json:"regions,omitempty"`
|
||||||
|
Available bool `json:"available,omitempty"`
|
||||||
|
Transfer float64 `json:"transfer,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Size) String() string {
|
func (s Size) String() string {
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,12 @@ package godo
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
var timestampType = reflect.TypeOf(Timestamp{})
|
var timestampType = reflect.TypeOf(Timestamp{})
|
||||||
|
|
||||||
// Stringify attempts to create a string representation of Digital Ocean types
|
// Stringify attempts to create a string representation of DigitalOcean types
|
||||||
func Stringify(message interface{}) string {
|
func Stringify(message interface{}) string {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
v := reflect.ValueOf(message)
|
v := reflect.ValueOf(message)
|
||||||
|
|
@ -18,9 +17,9 @@ func Stringify(message interface{}) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// stringifyValue was graciously cargoculted from the goprotubuf library
|
// stringifyValue was graciously cargoculted from the goprotubuf library
|
||||||
func stringifyValue(w io.Writer, val reflect.Value) {
|
func stringifyValue(w *bytes.Buffer, val reflect.Value) {
|
||||||
if val.Kind() == reflect.Ptr && val.IsNil() {
|
if val.Kind() == reflect.Ptr && val.IsNil() {
|
||||||
w.Write([]byte("<nil>"))
|
_, _ = w.Write([]byte("<nil>"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -30,20 +29,20 @@ func stringifyValue(w io.Writer, val reflect.Value) {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
fmt.Fprintf(w, `"%s"`, v)
|
fmt.Fprintf(w, `"%s"`, v)
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
w.Write([]byte{'['})
|
_, _ = w.Write([]byte{'['})
|
||||||
for i := 0; i < v.Len(); i++ {
|
for i := 0; i < v.Len(); i++ {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
w.Write([]byte{' '})
|
_, _ = w.Write([]byte{' '})
|
||||||
}
|
}
|
||||||
|
|
||||||
stringifyValue(w, v.Index(i))
|
stringifyValue(w, v.Index(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write([]byte{']'})
|
_, _ = w.Write([]byte{']'})
|
||||||
return
|
return
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
if v.Type().Name() != "" {
|
if v.Type().Name() != "" {
|
||||||
w.Write([]byte(v.Type().String()))
|
_, _ = w.Write([]byte(v.Type().String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// special handling of Timestamp values
|
// special handling of Timestamp values
|
||||||
|
|
@ -52,7 +51,7 @@ func stringifyValue(w io.Writer, val reflect.Value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write([]byte{'{'})
|
_, _ = w.Write([]byte{'{'})
|
||||||
|
|
||||||
var sep bool
|
var sep bool
|
||||||
for i := 0; i < v.NumField(); i++ {
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
|
@ -65,17 +64,17 @@ func stringifyValue(w io.Writer, val reflect.Value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if sep {
|
if sep {
|
||||||
w.Write([]byte(", "))
|
_, _ = w.Write([]byte(", "))
|
||||||
} else {
|
} else {
|
||||||
sep = true
|
sep = true
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write([]byte(v.Type().Field(i).Name))
|
_, _ = w.Write([]byte(v.Type().Field(i).Name))
|
||||||
w.Write([]byte{':'})
|
_, _ = w.Write([]byte{':'})
|
||||||
stringifyValue(w, fv)
|
stringifyValue(w, fv)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write([]byte{'}'})
|
_, _ = w.Write([]byte{'}'})
|
||||||
default:
|
default:
|
||||||
if v.CanInterface() {
|
if v.CanInterface() {
|
||||||
fmt.Fprint(w, v.Interface())
|
fmt.Fprint(w, v.Interface())
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ func (t Timestamp) String() string {
|
||||||
|
|
||||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||||
// Time is expected in RFC3339 or Unix format.
|
// Time is expected in RFC3339 or Unix format.
|
||||||
func (t *Timestamp) UnmarshalJSON(data []byte) (err error) {
|
func (t *Timestamp) UnmarshalJSON(data []byte) error {
|
||||||
str := string(data)
|
str := string(data)
|
||||||
i, err := strconv.ParseInt(str, 10, 64)
|
i, err := strconv.ParseInt(str, 10, 64)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
@ -26,7 +26,7 @@ func (t *Timestamp) UnmarshalJSON(data []byte) (err error) {
|
||||||
} else {
|
} else {
|
||||||
t.Time, err = time.Parse(`"`+time.RFC3339+`"`, str)
|
t.Time, err = time.Parse(`"`+time.RFC3339+`"`, str)
|
||||||
}
|
}
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equal reports whether t and u are equal based on time.Equal
|
// Equal reports whether t and u are equal based on time.Equal
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/digitaloceancloud/godo"
|
"github.com/digitalocean/godo"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue