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