blob: 04faf3227d03f9b49b87eba16fb4b6a430adbeb8 [file] [log] [blame]
package backups
import (
"fmt"
"reflect"
"time"
"github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/openstack/db/v1/datastores"
"github.com/rackspace/gophercloud/pagination"
)
// Status represents the various states a Backup can be in.
type Status string
// Enum types for the status.
const (
StatusNew Status = "NEW"
StatusBuilding Status = "BUILDING"
StatusCompleted Status = "COMPLETED"
StatusFailed Status = "FAILED"
StatusDeleteFailed Status = "DELETE_FAILED"
)
// Backup represents a Backup API resource.
type Backup struct {
Description string
ID string
InstanceID string `json:"instance_id" mapstructure:"instance_id"`
LocationRef string
Name string
ParentID string `json:"parent_id" mapstructure:"parent_id"`
Size float64
Status Status
Created time.Time `mapstructure:"-"`
Updated time.Time `mapstructure:"-"`
Datastore datastores.DatastorePartial
}
// CreateResult represents the result of a create operation.
type CreateResult struct {
commonResult
}
// GetResult represents the result of a get operation.
type GetResult struct {
commonResult
}
// DeleteResult represents the result of a delete operation.
type DeleteResult struct {
gophercloud.ErrResult
}
type commonResult struct {
gophercloud.Result
}
// Extract will retrieve a Backup struct from an operation's result.
func (r commonResult) Extract() (*Backup, error) {
if r.Err != nil {
return nil, r.Err
}
var response struct {
Backup Backup `mapstructure:"backup"`
}
err := mapstructure.Decode(r.Body, &response)
val := r.Body.(map[string]interface{})["backup"].(map[string]interface{})
if t, ok := val["created"].(string); ok && t != "" {
creationTime, err := time.Parse(time.RFC3339, t)
if err != nil {
return &response.Backup, err
}
response.Backup.Created = creationTime
}
if t, ok := val["updated"].(string); ok && t != "" {
updatedTime, err := time.Parse(time.RFC3339, t)
if err != nil {
return &response.Backup, err
}
response.Backup.Updated = updatedTime
}
return &response.Backup, err
}
// BackupPage represents a page of backups.
type BackupPage struct {
pagination.SinglePageBase
}
// IsEmpty checks whether an BackupPage struct is empty.
func (r BackupPage) IsEmpty() (bool, error) {
is, err := ExtractBackups(r)
if err != nil {
return true, err
}
return len(is) == 0, nil
}
// ExtractBackups will retrieve a slice of Backup structs from a paginated collection.
func ExtractBackups(page pagination.Page) ([]Backup, error) {
casted := page.(BackupPage).Body
var resp struct {
Backups []Backup `mapstructure:"backups" json:"backups"`
}
if err := mapstructure.Decode(casted, &resp); err != nil {
return nil, err
}
var vals []interface{}
switch casted.(type) {
case map[string]interface{}:
vals = casted.(map[string]interface{})["backups"].([]interface{})
case map[string][]interface{}:
vals = casted.(map[string][]interface{})["backups"]
default:
return resp.Backups, fmt.Errorf("Unknown type: %v", reflect.TypeOf(casted))
}
for i, v := range vals {
val := v.(map[string]interface{})
if t, ok := val["created"].(string); ok && t != "" {
creationTime, err := time.Parse(time.RFC3339, t)
if err != nil {
return resp.Backups, err
}
resp.Backups[i].Created = creationTime
}
if t, ok := val["updated"].(string); ok && t != "" {
updatedTime, err := time.Parse(time.RFC3339, t)
if err != nil {
return resp.Backups, err
}
resp.Backups[i].Updated = updatedTime
}
}
return resp.Backups, nil
}