blob: e7b0847363726285dde4956062a215ae4f98382d [file] [log] [blame]
Jamie Hannafordff08ef92014-10-20 16:10:12 +02001package snapshots
2
3import (
Jamie Hannaford3a3d0ee2014-10-23 14:48:20 +02004 "fmt"
5 "time"
6
7 "github.com/racker/perigee"
8
Jamie Hannafordff08ef92014-10-20 16:10:12 +02009 "github.com/rackspace/gophercloud"
10 os "github.com/rackspace/gophercloud/openstack/blockstorage/v1/snapshots"
11 "github.com/rackspace/gophercloud/pagination"
12
13 "github.com/mitchellh/mapstructure"
14)
15
16// Status is the type used to represent a snapshot's status
17type Status string
18
19// Constants to use for supported statuses
20const (
21 Creating Status = "CREATING"
22 Available Status = "AVAILABLE"
23 Deleting Status = "DELETING"
24 Error Status = "ERROR"
25 DeleteError Status = "ERROR_DELETING"
26)
27
28// Snapshot is the Rackspace representation of an external block storage device.
29type Snapshot struct {
30 // The timestamp when this snapshot was created.
31 CreatedAt string `mapstructure:"created_at"`
32
33 // The human-readable description for this snapshot.
34 Description string `mapstructure:"display_description"`
35
36 // The human-readable name for this snapshot.
37 Name string `mapstructure:"display_name"`
38
39 // The UUID for this snapshot.
40 ID string `mapstructure:"id"`
41
42 // The random metadata associated with this snapshot. Note: unlike standard
43 // OpenStack snapshots, this cannot actually be set.
44 Metadata map[string]string `mapstructure:"metadata"`
45
46 // Indicates the current progress of the snapshot's backup procedure.
47 Progress string `mapstructure:"os-extended-snapshot-attributes:progress"`
48
49 // The project ID.
50 ProjectID string `mapstructure:"os-extended-snapshot-attributes:project_id"`
51
52 // The size of the volume which this snapshot backs up.
53 Size int `mapstructure:"size"`
54
55 // The status of the snapshot.
56 Status Status `mapstructure:"status"`
57
58 // The ID of the volume which this snapshot seeks to back up.
59 VolumeID string `mapstructure:"volume_id"`
60}
61
62type commonResult struct {
Jamie Hannafordeff7e8d2014-10-21 11:02:05 +020063 gophercloud.Result
Jamie Hannafordff08ef92014-10-20 16:10:12 +020064}
65
66// CreateResult represents the result of a create operation
67type CreateResult struct {
68 os.CreateResult
69}
70
71// GetResult represents the result of a get operation
72type GetResult struct {
73 os.GetResult
74}
75
Jamie Hannaford4a783952014-10-20 16:27:33 +020076// UpdateResult represents the result of an update operation
77type UpdateResult struct {
Jamie Hannafordeff7e8d2014-10-21 11:02:05 +020078 gophercloud.Result
Jamie Hannaford4a783952014-10-20 16:27:33 +020079}
80
Jamie Hannafordeff7e8d2014-10-21 11:02:05 +020081func commonExtract(resp interface{}, err error) (*Snapshot, error) {
Jamie Hannafordff08ef92014-10-20 16:10:12 +020082 if err != nil {
83 return nil, err
84 }
85
86 var respStruct struct {
87 Snapshot *Snapshot `json:"snapshot"`
88 }
89
90 err = mapstructure.Decode(resp, &respStruct)
91
92 return respStruct.Snapshot, err
93}
94
95// Extract will get the Snapshot object out of the GetResult object.
96func (r GetResult) Extract() (*Snapshot, error) {
Jamie Hannafordeff7e8d2014-10-21 11:02:05 +020097 return commonExtract(r.Body, r.Err)
Jamie Hannafordff08ef92014-10-20 16:10:12 +020098}
99
100// Extract will get the Snapshot object out of the CreateResult object.
101func (r CreateResult) Extract() (*Snapshot, error) {
Jamie Hannafordeff7e8d2014-10-21 11:02:05 +0200102 return commonExtract(r.Body, r.Err)
Jamie Hannafordff08ef92014-10-20 16:10:12 +0200103}
104
Jamie Hannaford4a783952014-10-20 16:27:33 +0200105// Extract will get the Snapshot object out of the UpdateResult object.
106func (r UpdateResult) Extract() (*Snapshot, error) {
Jamie Hannafordeff7e8d2014-10-21 11:02:05 +0200107 return commonExtract(r.Body, r.Err)
Jamie Hannaford4a783952014-10-20 16:27:33 +0200108}
109
Jamie Hannafordff08ef92014-10-20 16:10:12 +0200110// ExtractSnapshots extracts and returns Snapshots. It is used while iterating over a snapshots.List call.
111func ExtractSnapshots(page pagination.Page) ([]Snapshot, error) {
112 var response struct {
113 Snapshots []Snapshot `json:"snapshots"`
114 }
115
116 err := mapstructure.Decode(page.(os.ListResult).Body, &response)
117 return response.Snapshots, err
118}
Jamie Hannaford3a3d0ee2014-10-23 14:48:20 +0200119
120// WaitUntilComplete will continually poll a snapshot until it successfully
121// transitions to a specified state. It will do this for at most the number of
122// seconds specified.
123func (snapshot Snapshot) WaitUntilComplete(c *gophercloud.ServiceClient, timeout int) error {
124 start := time.Now().Second()
125 var err error
126 for {
127 current, err := Get(c, snapshot.ID).Extract()
128
129 if err != nil {
130 break
131 }
132 if timeout > 0 && time.Now().Second()-start >= timeout {
133 err = fmt.Errorf("A timeout occurred")
134 break
135 }
136
137 if current.Progress == "100%" {
138 break
139 }
140 }
141
142 return err
143}
144
145func (snapshot Snapshot) WaitUntilDeleted(c *gophercloud.ServiceClient, timeout int) error {
146 start := time.Now().Second()
147 var err error
148 for {
149 _, err := Get(c, snapshot.ID).Extract()
150
151 // We actually want an error here
152 if casted, ok := err.(*perigee.UnexpectedResponseCodeError); ok && casted.Actual == 404 {
153 err = nil
154 break
155 } else if err != nil {
156 break
157 }
158
159 if timeout > 0 && time.Now().Second()-start >= timeout {
160 err = fmt.Errorf("A timeout occurred")
161 break
162 }
163 }
164
165 return err
166}