1package godo
2
3import (
4	"context"
5	"fmt"
6	"net/http"
7)
8
9const snapshotBasePath = "v2/snapshots"
10
11// SnapshotsService is an interface for interfacing with the snapshots
12// endpoints of the DigitalOcean API
13// See: https://developers.digitalocean.com/documentation/v2#snapshots
14type SnapshotsService interface {
15	List(context.Context, *ListOptions) ([]Snapshot, *Response, error)
16	ListVolume(context.Context, *ListOptions) ([]Snapshot, *Response, error)
17	ListDroplet(context.Context, *ListOptions) ([]Snapshot, *Response, error)
18	Get(context.Context, string) (*Snapshot, *Response, error)
19	Delete(context.Context, string) (*Response, error)
20}
21
22// SnapshotsServiceOp handles communication with the snapshot related methods of the
23// DigitalOcean API.
24type SnapshotsServiceOp struct {
25	client *Client
26}
27
28var _ SnapshotsService = &SnapshotsServiceOp{}
29
30// Snapshot represents a DigitalOcean Snapshot
31type Snapshot struct {
32	ID            string   `json:"id,omitempty"`
33	Name          string   `json:"name,omitempty"`
34	ResourceID    string   `json:"resource_id,omitempty"`
35	ResourceType  string   `json:"resource_type,omitempty"`
36	Regions       []string `json:"regions,omitempty"`
37	MinDiskSize   int      `json:"min_disk_size,omitempty"`
38	SizeGigaBytes float64  `json:"size_gigabytes,omitempty"`
39	Created       string   `json:"created_at,omitempty"`
40}
41
42type snapshotRoot struct {
43	Snapshot *Snapshot `json:"snapshot"`
44}
45
46type snapshotsRoot struct {
47	Snapshots []Snapshot `json:"snapshots"`
48	Links     *Links     `json:"links,omitempty"`
49}
50
51type listSnapshotOptions struct {
52	ResourceType string `url:"resource_type,omitempty"`
53}
54
55func (s Snapshot) String() string {
56	return Stringify(s)
57}
58
59// List lists all the snapshots available.
60func (s *SnapshotsServiceOp) List(ctx context.Context, opt *ListOptions) ([]Snapshot, *Response, error) {
61	return s.list(ctx, opt, nil)
62}
63
64// ListDroplet lists all the Droplet snapshots.
65func (s *SnapshotsServiceOp) ListDroplet(ctx context.Context, opt *ListOptions) ([]Snapshot, *Response, error) {
66	listOpt := listSnapshotOptions{ResourceType: "droplet"}
67	return s.list(ctx, opt, &listOpt)
68}
69
70// ListVolume lists all the volume snapshots.
71func (s *SnapshotsServiceOp) ListVolume(ctx context.Context, opt *ListOptions) ([]Snapshot, *Response, error) {
72	listOpt := listSnapshotOptions{ResourceType: "volume"}
73	return s.list(ctx, opt, &listOpt)
74}
75
76// Get retrieves an snapshot by id.
77func (s *SnapshotsServiceOp) Get(ctx context.Context, snapshotID string) (*Snapshot, *Response, error) {
78	return s.get(ctx, snapshotID)
79}
80
81// Delete an snapshot.
82func (s *SnapshotsServiceOp) Delete(ctx context.Context, snapshotID string) (*Response, error) {
83	path := fmt.Sprintf("%s/%s", snapshotBasePath, snapshotID)
84
85	req, err := s.client.NewRequest(ctx, http.MethodDelete, path, nil)
86	if err != nil {
87		return nil, err
88	}
89
90	resp, err := s.client.Do(ctx, req, nil)
91
92	return resp, err
93}
94
95// Helper method for getting an individual snapshot
96func (s *SnapshotsServiceOp) get(ctx context.Context, ID string) (*Snapshot, *Response, error) {
97	path := fmt.Sprintf("%s/%s", snapshotBasePath, ID)
98
99	req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
100	if err != nil {
101		return nil, nil, err
102	}
103
104	root := new(snapshotRoot)
105	resp, err := s.client.Do(ctx, req, root)
106	if err != nil {
107		return nil, resp, err
108	}
109
110	return root.Snapshot, resp, err
111}
112
113// Helper method for listing snapshots
114func (s *SnapshotsServiceOp) list(ctx context.Context, opt *ListOptions, listOpt *listSnapshotOptions) ([]Snapshot, *Response, error) {
115	path := snapshotBasePath
116	path, err := addOptions(path, opt)
117	if err != nil {
118		return nil, nil, err
119	}
120	path, err = addOptions(path, listOpt)
121	if err != nil {
122		return nil, nil, err
123	}
124
125	req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
126	if err != nil {
127		return nil, nil, err
128	}
129
130	root := new(snapshotsRoot)
131	resp, err := s.client.Do(ctx, req, root)
132	if err != nil {
133		return nil, resp, err
134	}
135	if l := root.Links; l != nil {
136		resp.Links = l
137	}
138
139	return root.Snapshots, resp, err
140}
141