| Jon Perritt | 3711cd0 | 2014-12-22 22:20:15 -0700 | [diff] [blame] | 1 | package stackresources | 
 | 2 |  | 
 | 3 | import ( | 
 | 4 | 	"time" | 
 | 5 |  | 
 | 6 | 	"github.com/mitchellh/mapstructure" | 
 | 7 | 	"github.com/rackspace/gophercloud" | 
 | 8 | 	"github.com/rackspace/gophercloud/pagination" | 
 | 9 | ) | 
 | 10 |  | 
 | 11 | type Resource struct { | 
 | 12 | 	Links        []gophercloud.Link `mapstructure:"links"` | 
 | 13 | 	LogicalID    string             `mapstructure:"logical_resource_id"` | 
 | 14 | 	Name         string             `mapstructure:"resource_name"` | 
 | 15 | 	PhysicalID   string             `mapstructure:"physical_resource_id"` | 
 | 16 | 	RequiredBy   []interface{}      `mapstructure:"required_by"` | 
 | 17 | 	Status       string             `mapstructure:"resource_status"` | 
 | 18 | 	StatusReason string             `mapstructure:"resource_status_reason"` | 
 | 19 | 	Type         string             `mapstructure:"resource_type"` | 
 | 20 | 	UpdatedTime  time.Time          `mapstructure:"-"` | 
 | 21 | } | 
 | 22 |  | 
 | 23 | type FindResult struct { | 
 | 24 | 	gophercloud.Result | 
 | 25 | } | 
 | 26 |  | 
 | 27 | func (r FindResult) Extract() ([]Resource, error) { | 
 | 28 | 	if r.Err != nil { | 
 | 29 | 		return nil, r.Err | 
 | 30 | 	} | 
 | 31 |  | 
 | 32 | 	var res struct { | 
 | 33 | 		Res []Resource `mapstructure:"resources"` | 
 | 34 | 	} | 
 | 35 |  | 
 | 36 | 	if err := mapstructure.Decode(r.Body, &res); err != nil { | 
 | 37 | 		return nil, err | 
 | 38 | 	} | 
 | 39 |  | 
| Jon Perritt | a065da1 | 2015-02-06 10:20:16 -0700 | [diff] [blame^] | 40 | 	resources := r.Body.(map[string]interface{})["resources"].([]interface{}) | 
| Jon Perritt | 3711cd0 | 2014-12-22 22:20:15 -0700 | [diff] [blame] | 41 |  | 
| Jon Perritt | a065da1 | 2015-02-06 10:20:16 -0700 | [diff] [blame^] | 42 | 	for i, resourceRaw := range resources { | 
 | 43 | 		resource := resourceRaw.(map[string]interface{}) | 
| Jon Perritt | 3711cd0 | 2014-12-22 22:20:15 -0700 | [diff] [blame] | 44 | 		if date, ok := resource["updated_time"]; ok && date != nil { | 
 | 45 | 			t, err := time.Parse(time.RFC3339, date.(string)) | 
 | 46 | 			if err != nil { | 
 | 47 | 				return nil, err | 
 | 48 | 			} | 
 | 49 | 			res.Res[i].UpdatedTime = t | 
 | 50 | 		} | 
 | 51 | 	} | 
 | 52 |  | 
 | 53 | 	return res.Res, nil | 
 | 54 | } | 
 | 55 |  | 
 | 56 | // ResourcePage abstracts the raw results of making a List() request against the API. | 
 | 57 | // As OpenStack extensions may freely alter the response bodies of structures returned to the client, you may only safely access the | 
 | 58 | // data provided through the ExtractResources call. | 
 | 59 | type ResourcePage struct { | 
 | 60 | 	pagination.LinkedPageBase | 
 | 61 | } | 
 | 62 |  | 
 | 63 | // IsEmpty returns true if a page contains no Server results. | 
 | 64 | func (page ResourcePage) IsEmpty() (bool, error) { | 
 | 65 | 	resources, err := ExtractResources(page) | 
 | 66 | 	if err != nil { | 
 | 67 | 		return true, err | 
 | 68 | 	} | 
 | 69 | 	return len(resources) == 0, nil | 
 | 70 | } | 
 | 71 |  | 
 | 72 | // NextPageURL uses the response's embedded link reference to navigate to the next page of results. | 
 | 73 | func (page ResourcePage) NextPageURL() (string, error) { | 
 | 74 | 	type resp struct { | 
 | 75 | 		Links []gophercloud.Link `mapstructure:"servers_links"` | 
 | 76 | 	} | 
 | 77 |  | 
 | 78 | 	var r resp | 
 | 79 | 	err := mapstructure.Decode(page.Body, &r) | 
 | 80 | 	if err != nil { | 
 | 81 | 		return "", err | 
 | 82 | 	} | 
 | 83 |  | 
 | 84 | 	return gophercloud.ExtractNextURL(r.Links) | 
 | 85 | } | 
 | 86 |  | 
 | 87 | // ExtractResources interprets the results of a single page from a List() call, producing a slice of Resource entities. | 
 | 88 | func ExtractResources(page pagination.Page) ([]Resource, error) { | 
 | 89 | 	casted := page.(ResourcePage).Body | 
 | 90 |  | 
 | 91 | 	var response struct { | 
 | 92 | 		Resources []Resource `mapstructure:"resources"` | 
 | 93 | 	} | 
 | 94 | 	err := mapstructure.Decode(casted, &response) | 
| Jon Perritt | a065da1 | 2015-02-06 10:20:16 -0700 | [diff] [blame^] | 95 |  | 
 | 96 | 	resources := casted.(map[string]interface{})["resources"].([]interface{}) | 
 | 97 |  | 
 | 98 | 	for i, resourceRaw := range resources { | 
 | 99 | 		resource := resourceRaw.(map[string]interface{}) | 
 | 100 | 		if date, ok := resource["updated_time"]; ok && date != nil { | 
 | 101 | 			t, err := time.Parse(time.RFC3339, date.(string)) | 
 | 102 | 			if err != nil { | 
 | 103 | 				return nil, err | 
 | 104 | 			} | 
 | 105 | 			response.Resources[i].UpdatedTime = t | 
 | 106 | 		} | 
 | 107 | 	} | 
 | 108 |  | 
| Jon Perritt | 3711cd0 | 2014-12-22 22:20:15 -0700 | [diff] [blame] | 109 | 	return response.Resources, err | 
 | 110 | } | 
 | 111 |  | 
 | 112 | type GetResult struct { | 
 | 113 | 	gophercloud.Result | 
 | 114 | } | 
 | 115 |  | 
 | 116 | func (r GetResult) Extract() (*Resource, error) { | 
 | 117 | 	if r.Err != nil { | 
 | 118 | 		return nil, r.Err | 
 | 119 | 	} | 
 | 120 |  | 
 | 121 | 	var res struct { | 
 | 122 | 		Res *Resource `mapstructure:"resource"` | 
 | 123 | 	} | 
 | 124 |  | 
 | 125 | 	if err := mapstructure.Decode(r.Body, &res); err != nil { | 
 | 126 | 		return nil, err | 
 | 127 | 	} | 
 | 128 |  | 
 | 129 | 	resource := r.Body.(map[string]interface{})["resource"].(map[string]interface{}) | 
 | 130 |  | 
 | 131 | 	if date, ok := resource["updated_time"]; ok && date != nil { | 
 | 132 | 		t, err := time.Parse(time.RFC3339, date.(string)) | 
 | 133 | 		if err != nil { | 
 | 134 | 			return nil, err | 
 | 135 | 		} | 
 | 136 | 		res.Res.UpdatedTime = t | 
 | 137 | 	} | 
 | 138 |  | 
 | 139 | 	return res.Res, nil | 
 | 140 | } | 
 | 141 |  | 
 | 142 | type MetadataResult struct { | 
 | 143 | 	gophercloud.Result | 
 | 144 | } | 
 | 145 |  | 
 | 146 | func (r MetadataResult) Extract() (map[string]string, error) { | 
 | 147 | 	if r.Err != nil { | 
 | 148 | 		return nil, r.Err | 
 | 149 | 	} | 
 | 150 |  | 
 | 151 | 	var res struct { | 
 | 152 | 		Meta map[string]string `mapstructure:"metadata"` | 
 | 153 | 	} | 
 | 154 |  | 
 | 155 | 	if err := mapstructure.Decode(r.Body, &res); err != nil { | 
 | 156 | 		return nil, err | 
 | 157 | 	} | 
 | 158 |  | 
 | 159 | 	return res.Meta, nil | 
 | 160 | } | 
| Jon Perritt | a065da1 | 2015-02-06 10:20:16 -0700 | [diff] [blame^] | 161 |  | 
 | 162 | // ResourceTypePage abstracts the raw results of making a ListTypes() request against the API. | 
 | 163 | // As OpenStack extensions may freely alter the response bodies of structures returned to the client, you may only safely access the | 
 | 164 | // data provided through the ExtractResourceTypes call. | 
 | 165 | type ResourceTypePage struct { | 
 | 166 | 	pagination.SinglePageBase | 
 | 167 | } | 
 | 168 |  | 
 | 169 | // IsEmpty returns true if a ResourceTypePage contains no resource types. | 
 | 170 | func (r ResourceTypePage) IsEmpty() (bool, error) { | 
 | 171 | 	rts, err := ExtractResourceTypes(r) | 
 | 172 | 	if err != nil { | 
 | 173 | 		return true, err | 
 | 174 | 	} | 
 | 175 | 	return len(rts) == 0, nil | 
 | 176 | } | 
 | 177 |  | 
 | 178 | // ExtractResourceTypes extracts and returns resource types. | 
 | 179 | func ExtractResourceTypes(page pagination.Page) ([]string, error) { | 
 | 180 | 	var response struct { | 
 | 181 | 		ResourceTypes []string `mapstructure:"resource_types"` | 
 | 182 | 	} | 
 | 183 |  | 
 | 184 | 	err := mapstructure.Decode(page.(ResourceTypePage).Body, &response) | 
 | 185 | 	return response.ResourceTypes, err | 
 | 186 | } |