1package backups
2
3import (
4	"encoding/json"
5	"time"
6
7	"github.com/gophercloud/gophercloud"
8	"github.com/gophercloud/gophercloud/pagination"
9)
10
11// Backup contains all the information associated with a Cinder Backup.
12type Backup struct {
13	// ID is the Unique identifier of the backup.
14	ID string `json:"id"`
15
16	// CreatedAt is the date the backup was created.
17	CreatedAt time.Time `json:"-"`
18
19	// UpdatedAt is the date the backup was updated.
20	UpdatedAt time.Time `json:"-"`
21
22	// Name is the display name of the backup.
23	Name string `json:"name"`
24
25	// Description is the description of the backup.
26	Description string `json:"description"`
27
28	// VolumeID is the ID of the Volume from which this backup was created.
29	VolumeID string `json:"volume_id"`
30
31	// SnapshotID is the ID of the snapshot from which this backup was created.
32	SnapshotID string `json:"snapshot_id"`
33
34	// Status is the status of the backup.
35	Status string `json:"status"`
36
37	// Size is the size of the backup, in GB.
38	Size int `json:"size"`
39
40	// Object Count is the number of objects in the backup.
41	ObjectCount int `json:"object_count"`
42
43	// Container is the container where the backup is stored.
44	Container string `json:"container"`
45
46	// HasDependentBackups is whether there are other backups
47	// depending on this backup.
48	HasDependentBackups bool `json:"has_dependent_backups"`
49
50	// FailReason has the reason for the backup failure.
51	FailReason string `json:"fail_reason"`
52
53	// IsIncremental is whether this is an incremental backup.
54	IsIncremental bool `json:"is_incremental"`
55
56	// DataTimestamp is the time when the data on the volume was first saved.
57	DataTimestamp time.Time `json:"-"`
58
59	// ProjectID is the ID of the project that owns the backup. This is
60	// an admin-only field.
61	ProjectID string `json:"os-backup-project-attr:project_id"`
62
63	// Metadata is metadata about the backup.
64	// This requires microversion 3.43 or later.
65	Metadata *map[string]string `json:"metadata"`
66
67	// AvailabilityZone is the Availability Zone of the backup.
68	// This requires microversion 3.51 or later.
69	AvailabilityZone *string `json:"availability_zone"`
70}
71
72// CreateResult contains the response body and error from a Create request.
73type CreateResult struct {
74	commonResult
75}
76
77// GetResult contains the response body and error from a Get request.
78type GetResult struct {
79	commonResult
80}
81
82// DeleteResult contains the response body and error from a Delete request.
83type DeleteResult struct {
84	gophercloud.ErrResult
85}
86
87// BackupPage is a pagination.Pager that is returned from a call to the List function.
88type BackupPage struct {
89	pagination.LinkedPageBase
90}
91
92// UnmarshalJSON converts our JSON API response into our backup struct
93func (r *Backup) UnmarshalJSON(b []byte) error {
94	type tmp Backup
95	var s struct {
96		tmp
97		CreatedAt     gophercloud.JSONRFC3339MilliNoZ `json:"created_at"`
98		UpdatedAt     gophercloud.JSONRFC3339MilliNoZ `json:"updated_at"`
99		DataTimestamp gophercloud.JSONRFC3339MilliNoZ `json:"data_timestamp"`
100	}
101	err := json.Unmarshal(b, &s)
102	if err != nil {
103		return err
104	}
105	*r = Backup(s.tmp)
106
107	r.CreatedAt = time.Time(s.CreatedAt)
108	r.UpdatedAt = time.Time(s.UpdatedAt)
109	r.DataTimestamp = time.Time(s.DataTimestamp)
110
111	return err
112}
113
114// IsEmpty returns true if a BackupPage contains no Backups.
115func (r BackupPage) IsEmpty() (bool, error) {
116	volumes, err := ExtractBackups(r)
117	return len(volumes) == 0, err
118}
119
120func (page BackupPage) NextPageURL() (string, error) {
121	var s struct {
122		Links []gophercloud.Link `json:"backups_links"`
123	}
124	err := page.ExtractInto(&s)
125	if err != nil {
126		return "", err
127	}
128	return gophercloud.ExtractNextURL(s.Links)
129}
130
131// ExtractBackups extracts and returns Backups. It is used while iterating over a backups.List call.
132func ExtractBackups(r pagination.Page) ([]Backup, error) {
133	var s []Backup
134	err := ExtractBackupsInto(r, &s)
135	return s, err
136}
137
138// UpdateResult contains the response body and error from an Update request.
139type UpdateResult struct {
140	commonResult
141}
142
143type commonResult struct {
144	gophercloud.Result
145}
146
147// Extract will get the Backup object out of the commonResult object.
148func (r commonResult) Extract() (*Backup, error) {
149	var s Backup
150	err := r.ExtractInto(&s)
151	return &s, err
152}
153
154func (r commonResult) ExtractInto(v interface{}) error {
155	return r.Result.ExtractIntoStructPtr(v, "backup")
156}
157
158func ExtractBackupsInto(r pagination.Page, v interface{}) error {
159	return r.(BackupPage).Result.ExtractIntoSlicePtr(v, "backups")
160}
161
162// RestoreResult contains the response body and error from a restore request.
163type RestoreResult struct {
164	commonResult
165}
166
167// Restore contains all the information associated with a Cinder Backup restore
168// response.
169type Restore struct {
170	// BackupID is the Unique identifier of the backup.
171	BackupID string `json:"backup_id"`
172
173	// VolumeID is the Unique identifier of the volume.
174	VolumeID string `json:"volume_id"`
175
176	// Name is the name of the volume, where the backup was restored to.
177	VolumeName string `json:"volume_name"`
178}
179
180// Extract will get the Backup restore object out of the RestoreResult object.
181func (r RestoreResult) Extract() (*Restore, error) {
182	var s Restore
183	err := r.ExtractInto(&s)
184	return &s, err
185}
186
187func (r RestoreResult) ExtractInto(v interface{}) error {
188	return r.Result.ExtractIntoStructPtr(v, "restore")
189}
190
191// ExportResult contains the response body and error from an export request.
192type ExportResult struct {
193	commonResult
194}
195
196// BackupRecord contains an information about a backup backend storage.
197type BackupRecord struct {
198	// The service used to perform the backup.
199	BackupService string `json:"backup_service"`
200
201	// An identifier string to locate the backup.
202	BackupURL []byte `json:"backup_url"`
203}
204
205// Extract will get the Backup record object out of the ExportResult object.
206func (r ExportResult) Extract() (*BackupRecord, error) {
207	var s BackupRecord
208	err := r.ExtractInto(&s)
209	return &s, err
210}
211
212func (r ExportResult) ExtractInto(v interface{}) error {
213	return r.Result.ExtractIntoStructPtr(v, "backup-record")
214}
215
216// ImportResponse struct contains the response of the Backup Import action.
217type ImportResponse struct {
218	ID   string `json:"id"`
219	Name string `json:"name"`
220}
221
222// ImportResult contains the response body and error from an import request.
223type ImportResult struct {
224	gophercloud.Result
225}
226
227// Extract will get the Backup object out of the commonResult object.
228func (r ImportResult) Extract() (*ImportResponse, error) {
229	var s ImportResponse
230	err := r.ExtractInto(&s)
231	return &s, err
232}
233
234func (r ImportResult) ExtractInto(v interface{}) error {
235	return r.Result.ExtractIntoStructPtr(v, "backup")
236}
237
238// ImportBackup contains all the information to import a Cinder Backup.
239type ImportBackup struct {
240	ID                  string             `json:"id"`
241	CreatedAt           time.Time          `json:"-"`
242	UpdatedAt           time.Time          `json:"-"`
243	VolumeID            string             `json:"volume_id"`
244	SnapshotID          *string            `json:"snapshot_id"`
245	Status              *string            `json:"status"`
246	Size                *int               `json:"size"`
247	ObjectCount         *int               `json:"object_count"`
248	Container           *string            `json:"container"`
249	ServiceMetadata     *string            `json:"service_metadata"`
250	Service             *string            `json:"service"`
251	Host                *string            `json:"host"`
252	UserID              string             `json:"user_id"`
253	DeletedAt           time.Time          `json:"-"`
254	DataTimestamp       time.Time          `json:"-"`
255	TempSnapshotID      *string            `json:"temp_snapshot_id"`
256	TempVolumeID        *string            `json:"temp_volume_id"`
257	RestoreVolumeID     *string            `json:"restore_volume_id"`
258	NumDependentBackups *int               `json:"num_dependent_backups"`
259	EncryptionKeyID     *string            `json:"encryption_key_id"`
260	ParentID            *string            `json:"parent_id"`
261	Deleted             bool               `json:"deleted"`
262	DisplayName         *string            `json:"display_name"`
263	DisplayDescription  *string            `json:"display_description"`
264	DriverInfo          interface{}        `json:"driver_info"`
265	FailReason          *string            `json:"fail_reason"`
266	ProjectID           string             `json:"project_id"`
267	Metadata            *map[string]string `json:"metadata"`
268	AvailabilityZone    *string            `json:"availability_zone"`
269}
270
271// UnmarshalJSON converts our JSON API response into our backup struct
272func (r *ImportBackup) UnmarshalJSON(b []byte) error {
273	type tmp ImportBackup
274	var s struct {
275		tmp
276		CreatedAt     time.Time `json:"created_at"`
277		UpdatedAt     time.Time `json:"updated_at"`
278		DeletedAt     time.Time `json:"deleted_at"`
279		DataTimestamp time.Time `json:"data_timestamp"`
280	}
281	err := json.Unmarshal(b, &s)
282	if err != nil {
283		return err
284	}
285	*r = ImportBackup(s.tmp)
286
287	r.CreatedAt = time.Time(s.CreatedAt)
288	r.UpdatedAt = time.Time(s.UpdatedAt)
289	r.DeletedAt = time.Time(s.DeletedAt)
290	r.DataTimestamp = time.Time(s.DataTimestamp)
291
292	return err
293}
294
295// MarshalJSON converts our struct request into JSON backup import request
296func (r ImportBackup) MarshalJSON() ([]byte, error) {
297	type b ImportBackup
298	type ext struct {
299		CreatedAt     *string `json:"created_at"`
300		UpdatedAt     *string `json:"updated_at"`
301		DeletedAt     *string `json:"deleted_at"`
302		DataTimestamp *string `json:"data_timestamp"`
303	}
304	type tmp struct {
305		b
306		ext
307	}
308
309	var t ext
310	if r.CreatedAt != (time.Time{}) {
311		v := r.CreatedAt.Format(time.RFC3339)
312		t.CreatedAt = &v
313	}
314	if r.UpdatedAt != (time.Time{}) {
315		v := r.UpdatedAt.Format(time.RFC3339)
316		t.UpdatedAt = &v
317	}
318	if r.DeletedAt != (time.Time{}) {
319		v := r.DeletedAt.Format(time.RFC3339)
320		t.DeletedAt = &v
321	}
322	if r.DataTimestamp != (time.Time{}) {
323		v := r.DataTimestamp.Format(time.RFC3339)
324		t.DataTimestamp = &v
325	}
326
327	s := tmp{
328		b(r),
329		t,
330	}
331
332	return json.Marshal(s)
333}
334