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