Skip to content

Commit

Permalink
storage: support for storage API
Browse files Browse the repository at this point in the history
  • Loading branch information
aybabtme committed Jun 27, 2016
1 parent cacf7fa commit 39ac4f1
Show file tree
Hide file tree
Showing 7 changed files with 835 additions and 11 deletions.
23 changes: 23 additions & 0 deletions droplets.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ type Droplet struct {
Created string `json:"created_at,omitempty"`
Kernel *Kernel `json:"kernel,omitempty"`
Tags []string `json:"tags,ommitempty"`
DriveIDs []string `json:"drives"`
}

// PublicIPv4 returns the public IPv4 address for the Droplet.
Expand Down Expand Up @@ -146,6 +147,27 @@ type DropletCreateImage struct {
Slug string
}

// DropletCreateDrive identifies a drive to attach for the create request. It
// prefers Name over ID,
type DropletCreateDrive struct {
ID string
Name string
}

// MarshalJSON returns an object with either the name or id of the drive. It
// returns the id if the name is empty.
func (d DropletCreateDrive) MarshalJSON() ([]byte, error) {
if d.Name != "" {
return json.Marshal(struct {
Name string `json:"name"`
}{Name: d.Name})
}

return json.Marshal(struct {
ID string `json:"id"`
}{ID: d.ID})
}

// 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) {
Expand Down Expand Up @@ -183,6 +205,7 @@ type DropletCreateRequest struct {
IPv6 bool `json:"ipv6"`
PrivateNetworking bool `json:"private_networking"`
UserData string `json:"user_data,omitempty"`
Drives []DropletCreateDrive `json:"drives,omitempty"`
}

// DropletMultiCreateRequest is a request to create multiple droplets.
Expand Down
30 changes: 20 additions & 10 deletions droplets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func TestDroplets_ListDroplets(t *testing.T) {

expected := []Droplet{{ID: 1}, {ID: 2}}
if !reflect.DeepEqual(droplets, expected) {
t.Errorf("Droplets.List returned %+v, expected %+v", droplets, expected)
t.Errorf("Droplets.List\n got=%#v\nwant=%#v", droplets, expected)
}
}

Expand Down Expand Up @@ -132,7 +132,7 @@ func TestDroplets_GetDroplet(t *testing.T) {

expected := &Droplet{ID: 12345}
if !reflect.DeepEqual(droplets, expected) {
t.Errorf("Droplets.Get returned %+v, expected %+v", droplets, expected)
t.Errorf("Droplets.Get\n got=%#v\nwant=%#v", droplets, expected)
}
}

Expand All @@ -147,6 +147,11 @@ func TestDroplets_Create(t *testing.T) {
Image: DropletCreateImage{
ID: 1,
},
Drives: []DropletCreateDrive{
{Name: "hello-im-a-drive"},
{ID: "hello-im-another-drive"},
{Name: "hello-im-still-a-drive", ID: "should be ignored due to Name"},
},
}

mux.HandleFunc("/v2/droplets", func(w http.ResponseWriter, r *http.Request) {
Expand All @@ -159,6 +164,11 @@ func TestDroplets_Create(t *testing.T) {
"backups": false,
"ipv6": false,
"private_networking": false,
"drives": []interface{}{
map[string]interface{}{"name": "hello-im-a-drive"},
map[string]interface{}{"id": "hello-im-another-drive"},
map[string]interface{}{"name": "hello-im-still-a-drive"},
},
}

var v map[string]interface{}
Expand All @@ -168,7 +178,7 @@ func TestDroplets_Create(t *testing.T) {
}

if !reflect.DeepEqual(v, expected) {
t.Errorf("Request body = %#v, expected %#v", v, expected)
t.Errorf("Request body\n got=%#v\nwant=%#v", v, expected)
}

fmt.Fprintf(w, `{"droplet":{"id":1}, "links":{"actions": [{"id": 1, "href": "http://example.com", "rel": "create"}]}}`)
Expand Down Expand Up @@ -293,7 +303,7 @@ func TestDroplets_Kernels(t *testing.T) {

expected := []Kernel{{ID: 1}, {ID: 2}}
if !reflect.DeepEqual(kernels, expected) {
t.Errorf("Droplets.Kernels returned %+v, expected %+v", kernels, expected)
t.Errorf("Droplets.Kernels\n got=%#v\nwant=%#v", kernels, expected)
}
}

Expand All @@ -314,7 +324,7 @@ func TestDroplets_Snapshots(t *testing.T) {

expected := []Image{{ID: 1}, {ID: 2}}
if !reflect.DeepEqual(snapshots, expected) {
t.Errorf("Droplets.Snapshots returned %+v, expected %+v", snapshots, expected)
t.Errorf("Droplets.Snapshots\n got=%#v\nwant=%#v", snapshots, expected)
}
}

Expand All @@ -335,7 +345,7 @@ func TestDroplets_Backups(t *testing.T) {

expected := []Image{{ID: 1}, {ID: 2}}
if !reflect.DeepEqual(backups, expected) {
t.Errorf("Droplets.Backups returned %+v, expected %+v", backups, expected)
t.Errorf("Droplets.Backups\n got=%#v\nwant=%#v", backups, expected)
}
}

Expand All @@ -356,7 +366,7 @@ func TestDroplets_Actions(t *testing.T) {

expected := []Action{{ID: 1}, {ID: 2}}
if !reflect.DeepEqual(actions, expected) {
t.Errorf("Droplets.Actions returned %+v, expected %+v", actions, expected)
t.Errorf("Droplets.Actions\n got=%#v\nwant=%#v", actions, expected)
}
}

Expand All @@ -376,7 +386,7 @@ func TestDroplets_Neighbors(t *testing.T) {

expected := []Droplet{{ID: 1}, {ID: 2}}
if !reflect.DeepEqual(neighbors, expected) {
t.Errorf("Droplets.Neighbors returned %+v, expected %+v", neighbors, expected)
t.Errorf("Droplets.Neighbors\n got=%#v\nwant=%#v", neighbors, expected)
}
}

Expand All @@ -390,7 +400,7 @@ func TestNetworkV4_String(t *testing.T) {
stringified := network.String()
expected := `godo.NetworkV4{IPAddress:"192.168.1.2", Netmask:"255.255.255.0", Gateway:"192.168.1.1", Type:""}`
if expected != stringified {
t.Errorf("NetworkV4.String returned %+v, expected %+v", stringified, expected)
t.Errorf("NetworkV4.String\n got=%#v\nwant=%#v", stringified, expected)
}

}
Expand All @@ -404,7 +414,7 @@ func TestNetworkV6_String(t *testing.T) {
stringified := network.String()
expected := `godo.NetworkV6{IPAddress:"2604:A880:0800:0010:0000:0000:02DD:4001", Netmask:64, Gateway:"2604:A880:0800:0010:0000:0000:0000:0001", Type:""}`
if expected != stringified {
t.Errorf("NetworkV6.String returned %+v, expected %+v", stringified, expected)
t.Errorf("NetworkV6.String\n got=%#v\nwant=%#v", stringified, expected)
}
}

Expand Down
13 changes: 12 additions & 1 deletion godo.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ type Client struct {
Sizes SizesService
FloatingIPs FloatingIPsService
FloatingIPActions FloatingIPActionsService
Storage StorageService
StorageActions StorageActionsService
Tags TagsService

// Optional function called after every successful request made to the DO APIs
Expand Down Expand Up @@ -94,7 +96,10 @@ type ErrorResponse struct {
Response *http.Response

// Error message
Message string
Message string `json:"message"`

// RequestID returned from the API, useful to contact support.
RequestID string `json:"request_id"`
}

// Rate contains the rate limit for the current client.
Expand Down Expand Up @@ -157,6 +162,8 @@ func NewClient(httpClient *http.Client) *Client {
c.Sizes = &SizesServiceOp{client: c}
c.FloatingIPs = &FloatingIPsServiceOp{client: c}
c.FloatingIPActions = &FloatingIPActionsServiceOp{client: c}
c.Storage = &StorageServiceOp{client: c}
c.StorageActions = &StorageActionsServiceOp{client: c}
c.Tags = &TagsServiceOp{client: c}

return c
Expand Down Expand Up @@ -318,6 +325,10 @@ func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
return response, err
}
func (r *ErrorResponse) Error() string {
if r.RequestID != "" {
return fmt.Sprintf("%v %v: %d (request %q) %v",
r.Response.Request.Method, r.Response.Request.URL, r.Response.StatusCode, r.RequestID, r.Message)
}
return fmt.Sprintf("%v %v: %d %v",
r.Response.Request.Method, r.Response.Request.URL, r.Response.StatusCode, r.Message)
}
Expand Down
Loading

0 comments on commit 39ac4f1

Please sign in to comment.