Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/vol snapshots #226

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 62 additions & 8 deletions volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,15 @@ type VolumeResult struct {

// VolumeConfig are the settings required to create a new Volume
type VolumeConfig struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
ClusterID string `json:"cluster_id"`
NetworkID string `json:"network_id"`
Region string `json:"region"`
SizeGigabytes int `json:"size_gb"`
Bootable bool `json:"bootable"`
VolumeType string `json:"volume_type"`
Name string `json:"name"`
Namespace string `json:"namespace"`
ClusterID string `json:"cluster_id"`
NetworkID string `json:"network_id"`
Region string `json:"region"`
SizeGigabytes int `json:"size_gb"`
Bootable bool `json:"bootable"`
VolumeType string `json:"volume_type"`
SnapshotID *string `json:"snapshot_id,omitempty"`
}

// VolumeAttachConfig is the configuration used to attach volume
Expand Down Expand Up @@ -242,3 +243,56 @@ func (c *Client) DeleteVolume(id string) (*SimpleResponse, error) {

return c.DecodeSimpleResponse(resp)
}

// GetVolumeSnapshotByVolumeID retrieves a specific volume snapshot by volume ID and snapshot ID
func (c *Client) GetVolumeSnapshotByVolumeID(volumeID, snapshotID string) (VolumeSnapshot, error) {
resp, err := c.SendGetRequest(fmt.Sprintf("/v2/volumes/%s/snapshot/%s", volumeID, snapshotID))
if err != nil {
return VolumeSnapshot{}, decodeError(err)
}
var volumeSnapshot = VolumeSnapshot{}
if err := json.NewDecoder(bytes.NewReader(resp)).Decode(&volumeSnapshot); err != nil {
return VolumeSnapshot{}, err
}
return volumeSnapshot, nil
}

// ListVolumeSnapshotsByVolumeID returns all snapshots for a specific volume by volume ID
func (c *Client) ListVolumeSnapshotsByVolumeID(volumeID string) ([]VolumeSnapshot, error) {
resp, err := c.SendGetRequest(fmt.Sprintf("/v2/volumes/%s/snapshots", volumeID))
if err != nil {
return nil, decodeError(err)
}

var volumeSnapshots = make([]VolumeSnapshot, 0)
if err := json.NewDecoder(bytes.NewReader(resp)).Decode(&volumeSnapshots); err != nil {
return nil, err
}

return volumeSnapshots, nil
}

// CreateVolumeSnapshot creates a snapshot of a volume
func (c *Client) CreateVolumeSnapshot(volumeID string, config *VolumeSnapshotConfig) (*VolumeSnapshot, error) {
body, err := c.SendPostRequest(fmt.Sprintf("/v2/volumes/%s/snapshots", volumeID), config)
if err != nil {
return nil, decodeError(err)
}

var result = &VolumeSnapshot{}
if err := json.NewDecoder(bytes.NewReader(body)).Decode(result); err != nil {
return nil, err
}

return result, nil
}

// DeleteVolumeAndAllSnapshot deletes a volume and all its snapshots
func (c *Client) DeleteVolumeAndAllSnapshot(volumeID string) (*SimpleResponse, error) {
resp, err := c.SendDeleteRequest(fmt.Sprintf("/v2/volumes/%s?delete_snapshot=true", volumeID))
if err != nil {
return nil, decodeError(err)
}

return c.DecodeSimpleResponse(resp)
}
62 changes: 62 additions & 0 deletions volume_snapshot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package civogo

import (
"bytes"
"encoding/json"
"fmt"
)

// VolumeSnapshot is the point-in-time copy of a Volume
type VolumeSnapshot struct {
Name string `json:"name"`
SnapshotID string `json:"snapshot_id"`
SnapshotDescription string `json:"snapshot_description"`
VolumeID string `json:"volume_id"`
RestoreSize int `json:"restore_size"`
State string `json:"state"`
CreationTime string `json:"creation_time"`
}

// VolumeSnapshotConfig is the configuration for creating a new VolumeSnapshot
type VolumeSnapshotConfig struct {
Name string `json:"name"`
Description string `json:"description"`
}

// ListVolumeSnapshots returns all snapshots owned by the calling API account
func (c *Client) ListVolumeSnapshots() ([]VolumeSnapshot, error) {
resp, err := c.SendGetRequest("/v2/snapshots?resource_type=volume")
if err != nil {
return nil, decodeError(err)
}

var volumeSnapshots = make([]VolumeSnapshot, 0)
if err := json.NewDecoder(bytes.NewReader(resp)).Decode(&volumeSnapshots); err != nil {
return nil, err
}

return volumeSnapshots, nil
}

// GetVolumeSnapshot finds a volume by the full ID
func (c *Client) GetVolumeSnapshot(id string) (VolumeSnapshot, error) {
resp, err := c.SendGetRequest(fmt.Sprintf("/v2/snapshots/%s?resource_type=volume", id))
if err != nil {
return VolumeSnapshot{}, decodeError(err)
}
var volumeSnapshot = VolumeSnapshot{}
if err := json.NewDecoder(bytes.NewReader(resp)).Decode(&volumeSnapshot); err != nil {
return VolumeSnapshot{}, err
}
return volumeSnapshot, nil
}

// DeleteVolumeSnapshot deletes a volume snapshot
func (c *Client) DeleteVolumeSnapshot(id string) (*SimpleResponse, error) {
resp, err := c.SendDeleteRequest(fmt.Sprintf("/v2/snapshots/%s", id))
if err != nil {
return nil, decodeError(err)
}

return c.DecodeSimpleResponse(resp)
}
98 changes: 98 additions & 0 deletions volume_snapshot_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package civogo

import (
"reflect"
"testing"
)

func TestListVolumeSnapshots(t *testing.T) {
client, server, _ := NewClientForTesting(map[string]string{
"/v2/snapshots?region=TEST&resource_type=volume": `[{
"name": "test-snapshot",
"snapshot_id": "12345",
"snapshot_description": "snapshot for test",
"volume_id": "12345",
"restore_size": 20,
"state": "available",
"creation_time": "2020-01-01T00:00:00Z"
}]`,
})
defer server.Close()

got, err := client.ListVolumeSnapshots()

if err != nil {
t.Errorf("Request returned an error: %s", err)
return
}

expected := []VolumeSnapshot{
{
Name: "test-snapshot",
SnapshotID: "12345",
SnapshotDescription: "snapshot for test",
VolumeID: "12345",
RestoreSize: 20,
State: "available",
CreationTime: "2020-01-01T00:00:00Z",
},
}

if !reflect.DeepEqual(got, expected) {
t.Errorf("Expected %+v, got %+v", expected, got)
}
}

func TestGetVolumeSnapshot(t *testing.T) {
client, server, _ := NewClientForTesting(map[string]string{
"/v2/snapshots/snapshot-uuid?region=TEST&resource_type=volume": `{
"name": "test-snapshot",
"snapshot_id": "snapshot-uuid",
"snapshot_description": "snapshot for testing",
"volume_id": "12345",
"restore_size": 20,
"state": "available",
"creation_time": "2020-01-01T00:00:00Z"
}`,
})
defer server.Close()
got, err := client.GetVolumeSnapshot("snapshot-uuid")

if err != nil {
t.Errorf("Request returned an error: %s", err)
return
}

expected := VolumeSnapshot{
Name: "test-snapshot",
SnapshotID: "snapshot-uuid",
SnapshotDescription: "snapshot for testing",
VolumeID: "12345",
RestoreSize: 20,
State: "available",
CreationTime: "2020-01-01T00:00:00Z",
}

if !reflect.DeepEqual(got, expected) {
t.Errorf("Expected %+v, got %+v", expected, got)
}
}

func TestDeleteVolumeSnapshot(t *testing.T) {
client, server, _ := NewClientForTesting(map[string]string{
"/v2/snapshots/12346": `{"result": "success"}`,
})
defer server.Close()
got, err := client.DeleteVolumeSnapshot("12346")

if err != nil {
t.Errorf("Request returned an error: %s", err)
return
}

expected := &SimpleResponse{Result: "success"}

if !reflect.DeepEqual(got, expected) {
t.Errorf("Expected %+v, got %+v", expected, got)
}
}
121 changes: 121 additions & 0 deletions volume_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,124 @@ func TestResizeVolume(t *testing.T) {
t.Errorf("Expected %+v, got %+v", expected, got)
}
}

func TestCreateVolumeSnapshot(t *testing.T) {
client, server, _ := NewClientForTesting(map[string]string{
"/v2/volumes/12346/snapshot": `{
"snapshot_id": "12345",
"name": "test-snapshot",
"snapshot_description": "snapshot for testing",
"volume_id": "12346",
"state": "available",
"creation_time": "2020-01-01T00:00:00Z"
}`,
})
defer server.Close()
cfg := &VolumeSnapshotConfig{Name: "my-snapshot"}
got, err := client.CreateVolumeSnapshot("12346", cfg)
if err != nil {
t.Errorf("Request returned an error: %s", err)
return
}

expected := &VolumeSnapshot{
SnapshotID: "12345",
Name: "test-snapshot",
SnapshotDescription: "snapshot for testing",
VolumeID: "12346",
State: "available",
CreationTime: "2020-01-01T00:00:00Z",
}
if !reflect.DeepEqual(got, expected) {
t.Errorf("Expected %+v, got %+v", expected, got)
}
}

func TestGetVolumeSnapshotByVolumeID(t *testing.T) {
client, server, _ := NewClientForTesting(map[string]string{
"/v2/volumes/12346/snapshot/12345": `{
"snapshot_id": "12345",
"name": "test-snapshot",
"snapshot_description": "snapshot for testing",
"volume_id": "12346",
"state": "available",
"creation_time": "2020-01-01T00:00:00Z"
}`,
})
defer server.Close()

got, err := client.GetVolumeSnapshotByVolumeID("12346", "12345")
if err != nil {
t.Errorf("Request returned an error: %s", err)
return
}

expected := VolumeSnapshot{
SnapshotID: "12345",
Name: "test-snapshot",
SnapshotDescription: "snapshot for testing",
VolumeID: "12346",
State: "available",
CreationTime: "2020-01-01T00:00:00Z",
}

if !reflect.DeepEqual(got, expected) {
t.Errorf("Expected %+v, got %+v", expected, got)
}
}

func TestListVolumeSnapshotsByVolumeID(t *testing.T) {
client, server, _ := NewClientForTesting(map[string]string{
"/v2/volumes/12346/snapshots": `[{
"snapshot_id": "12345",
"name": "test-snapshot",
"snapshot_description": "snapshot for testing",
"volume_id": "12346",
"state": "available",
"creation_time": "2020-01-01T00:00:00Z"
}]`,
})
defer server.Close()

got, err := client.ListVolumeSnapshotsByVolumeID("12346")
if err != nil {
t.Errorf("Request returned an error: %s", err)
return
}

expected := []VolumeSnapshot{
{
SnapshotID: "12345",
Name: "test-snapshot",
SnapshotDescription: "snapshot for testing",
VolumeID: "12346",
State: "available",
CreationTime: "2020-01-01T00:00:00Z",
},
}

if !reflect.DeepEqual(got, expected) {
t.Errorf("Expected %+v, got %+v", expected, got)
}
}

func TestDeleteVolumeAndAllSnapshot(t *testing.T) {
client, server, _ := NewClientForTesting(map[string]string{
"/v2/volumes/12346?delete_snapshot=true": `{"result": "success"}`,
})
defer server.Close()

got, err := client.DeleteVolumeAndAllSnapshot("12346")
if err != nil {
t.Errorf("Request returned an error: %s", err)
return
}

expected := &SimpleResponse{
Result: "success",
}

if !reflect.DeepEqual(got, expected) {
t.Errorf("Expected %+v, got %+v", expected, got)
}
}
Loading