1/*
2Copyright 2018 The Doctl Authors All rights reserved.
3Licensed under the Apache License, Version 2.0 (the "License");
4you may not use this file except in compliance with the License.
5You may obtain a copy of the License at
6    http://www.apache.org/licenses/LICENSE-2.0
7Unless required by applicable law or agreed to in writing, software
8distributed under the License is distributed on an "AS IS" BASIS,
9WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10See the License for the specific language governing permissions and
11limitations under the License.
12*/
13
14package commands
15
16import (
17	"fmt"
18
19	"github.com/digitalocean/doctl"
20	"github.com/digitalocean/doctl/commands/displayers"
21	"github.com/digitalocean/doctl/do"
22	"github.com/gobwas/glob"
23	"github.com/spf13/cobra"
24)
25
26// Snapshot creates the snapshot command
27func Snapshot() *Command {
28	cmd := &Command{
29		Command: &cobra.Command{
30			Use:     "snapshot",
31			Aliases: []string{"s"},
32			Short:   "Access and manage snapshots",
33			Long:    "The subcommands of `doctl compute snapshot` allow you to manage and retrieve information about Droplet and block storage volume snapshots.",
34		},
35	}
36
37	snapshotDetail := `
38
39  - The snapshot's ID
40  - The snapshot's name
41  - The date and time when the snapshot was created
42  - The slugs of the datacenter regions in which the snapshot is available
43  - The type of resource the snapshot was made from, Droplet or volume, and its ID
44  - The minimum size in GB required for a Droplet or volume to use this snapshot
45  - The compressed, billable size of the snapshot
46`
47
48	cmdRunSnapshotList := CmdBuilder(cmd, RunSnapshotList, "list [glob]",
49		"List Droplet and volume snapshots", "List information about Droplet and block storage volume snapshots, including:"+snapshotDetail,
50		Writer, aliasOpt("ls"), displayerType(&displayers.Snapshot{}))
51	AddStringFlag(cmdRunSnapshotList, doctl.ArgResourceType, "", "", "Filter by resource type (`droplet` or `volume`)")
52	AddStringFlag(cmdRunSnapshotList, doctl.ArgRegionSlug, "", "", "Filter by regional availability")
53
54	CmdBuilder(cmd, RunSnapshotGet, "get <snapshot-id>...",
55		"Retrieve a Droplet or volume snapshot", "Retrieve information about a Droplet or block storage volume snapshot, including:"+snapshotDetail,
56		Writer, aliasOpt("g"), displayerType(&displayers.Snapshot{}))
57
58	cmdRunSnapshotDelete := CmdBuilder(cmd, RunSnapshotDelete, "delete <snapshot-id>...",
59		"Delete a snapshot of a Droplet or volume", "Delete a snapshot of a Droplet or volume by specifying its ID.",
60		Writer, aliasOpt("d"), displayerType(&displayers.Snapshot{}))
61	AddBoolFlag(cmdRunSnapshotDelete, doctl.ArgForce, doctl.ArgShortForce, false, "Delete the snapshot without confirmation")
62
63	return cmd
64}
65
66// RunSnapshotList returns a list of snapshots
67func RunSnapshotList(c *CmdConfig) error {
68	var err error
69	ss := c.Snapshots()
70
71	restype, err := c.Doit.GetString(c.NS, doctl.ArgResourceType)
72	if err != nil {
73		return err
74	}
75
76	region, err := c.Doit.GetString(c.NS, doctl.ArgRegionSlug)
77	if err != nil {
78		return err
79	}
80
81	matches := make([]glob.Glob, 0, len(c.Args))
82	for _, globStr := range c.Args {
83		g, err := glob.Compile(globStr)
84		if err != nil {
85			return fmt.Errorf("unknown glob %q", globStr)
86		}
87
88		matches = append(matches, g)
89	}
90
91	var matchedList []do.Snapshot
92	var list []do.Snapshot
93
94	if restype == "droplet" {
95		list, err = ss.ListDroplet()
96		if err != nil {
97			return err
98		}
99	} else if restype == "volume" {
100		list, err = ss.ListVolume()
101		if err != nil {
102			return err
103		}
104	} else {
105		list, err = ss.List()
106		if err != nil {
107			return err
108		}
109	}
110
111	for _, snapshot := range list {
112		var skip = true
113		if len(matches) == 0 {
114			skip = false
115		} else {
116			for _, m := range matches {
117				if m.Match(snapshot.ID) {
118					skip = false
119				}
120				if m.Match(snapshot.Name) {
121					skip = false
122				}
123			}
124		}
125
126		if !skip && region != "" {
127			for _, snapshotRegion := range snapshot.Regions {
128				if region != snapshotRegion {
129					skip = true
130				} else {
131					skip = false
132					break
133				}
134			}
135
136		}
137
138		if !skip {
139			matchedList = append(matchedList, snapshot)
140		}
141	}
142
143	item := &displayers.Snapshot{Snapshots: matchedList}
144	return c.Display(item)
145}
146
147// RunSnapshotGet returns a snapshot
148func RunSnapshotGet(c *CmdConfig) error {
149	if len(c.Args) == 0 {
150		return doctl.NewMissingArgsErr(c.NS)
151	}
152
153	ss := c.Snapshots()
154	ids := c.Args
155
156	matchedList := make([]do.Snapshot, 0, len(ids))
157
158	for _, id := range ids {
159		s, err := ss.Get(id)
160		if err != nil {
161			return err
162		}
163		matchedList = append(matchedList, *s)
164	}
165	item := &displayers.Snapshot{Snapshots: matchedList}
166	return c.Display(item)
167}
168
169// RunSnapshotDelete destroys snapshot(s) by id
170func RunSnapshotDelete(c *CmdConfig) error {
171	if len(c.Args) == 0 {
172		return doctl.NewMissingArgsErr(c.NS)
173	}
174
175	force, err := c.Doit.GetBool(c.NS, doctl.ArgForce)
176	if err != nil {
177		return err
178	}
179
180	ss := c.Snapshots()
181	ids := c.Args
182
183	if force || AskForConfirmDelete("snapshot", len(ids)) == nil {
184		for _, id := range ids {
185			err := ss.Delete(id)
186			if err != nil {
187				return err
188			}
189		}
190	} else {
191		return errOperationAborted
192	}
193	return nil
194}
195