1//
2// Copyright (c) 2018, Joyent, Inc. All rights reserved.
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at http://mozilla.org/MPL/2.0/.
7//
8
9package compute
10
11import (
12	"context"
13	"encoding/json"
14	"net/http"
15	"path"
16	"time"
17
18	"github.com/joyent/triton-go/client"
19	"github.com/pkg/errors"
20)
21
22type SnapshotsClient struct {
23	client *client.Client
24}
25
26type Snapshot struct {
27	Name    string
28	State   string
29	Created time.Time
30	Updated time.Time
31}
32
33type ListSnapshotsInput struct {
34	MachineID string
35}
36
37func (c *SnapshotsClient) List(ctx context.Context, input *ListSnapshotsInput) ([]*Snapshot, error) {
38	fullPath := path.Join("/", c.client.AccountName, "machines", input.MachineID, "snapshots")
39	reqInputs := client.RequestInput{
40		Method: http.MethodGet,
41		Path:   fullPath,
42	}
43	respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
44	if respReader != nil {
45		defer respReader.Close()
46	}
47	if err != nil {
48		return nil, errors.Wrap(err, "unable to list snapshots")
49	}
50
51	var result []*Snapshot
52	decoder := json.NewDecoder(respReader)
53	if err = decoder.Decode(&result); err != nil {
54		return nil, errors.Wrap(err, "unable to decode list snapshots response")
55	}
56
57	return result, nil
58}
59
60type GetSnapshotInput struct {
61	MachineID string
62	Name      string
63}
64
65func (c *SnapshotsClient) Get(ctx context.Context, input *GetSnapshotInput) (*Snapshot, error) {
66	fullPath := path.Join("/", c.client.AccountName, "machines", input.MachineID, "snapshots", input.Name)
67	reqInputs := client.RequestInput{
68		Method: http.MethodGet,
69		Path:   fullPath,
70	}
71	respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
72	if respReader != nil {
73		defer respReader.Close()
74	}
75	if err != nil {
76		return nil, errors.Wrap(err, "unable to get snapshot")
77	}
78
79	var result *Snapshot
80	decoder := json.NewDecoder(respReader)
81	if err = decoder.Decode(&result); err != nil {
82		return nil, errors.Wrap(err, "unable to decode get snapshot response")
83	}
84
85	return result, nil
86}
87
88type DeleteSnapshotInput struct {
89	MachineID string
90	Name      string
91}
92
93func (c *SnapshotsClient) Delete(ctx context.Context, input *DeleteSnapshotInput) error {
94	fullPath := path.Join("/", c.client.AccountName, "machines", input.MachineID, "snapshots", input.Name)
95	reqInputs := client.RequestInput{
96		Method: http.MethodDelete,
97		Path:   fullPath,
98	}
99	respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
100	if respReader != nil {
101		defer respReader.Close()
102	}
103	if err != nil {
104		return errors.Wrap(err, "unable to delete snapshot")
105	}
106
107	return nil
108}
109
110type StartMachineFromSnapshotInput struct {
111	MachineID string
112	Name      string
113}
114
115func (c *SnapshotsClient) StartMachine(ctx context.Context, input *StartMachineFromSnapshotInput) error {
116	fullPath := path.Join("/", c.client.AccountName, "machines", input.MachineID, "snapshots", input.Name)
117	reqInputs := client.RequestInput{
118		Method: http.MethodPost,
119		Path:   fullPath,
120	}
121	respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
122	if respReader != nil {
123		defer respReader.Close()
124	}
125	if err != nil {
126		return errors.Wrap(err, "unable to start machine")
127	}
128
129	return nil
130}
131
132type CreateSnapshotInput struct {
133	MachineID string
134	Name      string
135}
136
137func (c *SnapshotsClient) Create(ctx context.Context, input *CreateSnapshotInput) (*Snapshot, error) {
138	fullPath := path.Join("/", c.client.AccountName, "machines", input.MachineID, "snapshots")
139
140	data := make(map[string]interface{})
141	data["name"] = input.Name
142
143	reqInputs := client.RequestInput{
144		Method: http.MethodPost,
145		Path:   fullPath,
146		Body:   data,
147	}
148
149	respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
150	if respReader != nil {
151		defer respReader.Close()
152	}
153	if err != nil {
154		return nil, errors.Wrap(err, "unable to create snapshot")
155	}
156
157	var result *Snapshot
158	decoder := json.NewDecoder(respReader)
159	if err = decoder.Decode(&result); err != nil {
160		return nil, errors.Wrap(err, "unable to decode create snapshot response")
161	}
162
163	return result, nil
164}
165