github.com/skyscape-cloud-services/terraform@v0.9.2-0.20170609144644-7ece028a1747/builtin/providers/openstack/types.go (about) 1 package openstack 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "log" 10 "net/http" 11 "strings" 12 13 "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs" 14 "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups" 15 "github.com/gophercloud/gophercloud/openstack/dns/v2/recordsets" 16 "github.com/gophercloud/gophercloud/openstack/dns/v2/zones" 17 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls" 18 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/policies" 19 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/routerinsertion" 20 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/rules" 21 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips" 22 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers" 23 "github.com/gophercloud/gophercloud/openstack/networking/v2/networks" 24 "github.com/gophercloud/gophercloud/openstack/networking/v2/ports" 25 "github.com/gophercloud/gophercloud/openstack/networking/v2/subnets" 26 ) 27 28 // LogRoundTripper satisfies the http.RoundTripper interface and is used to 29 // customize the default http client RoundTripper to allow for logging. 30 type LogRoundTripper struct { 31 Rt http.RoundTripper 32 OsDebug bool 33 } 34 35 // RoundTrip performs a round-trip HTTP request and logs relevant information about it. 36 func (lrt *LogRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) { 37 defer func() { 38 if request.Body != nil { 39 request.Body.Close() 40 } 41 }() 42 43 // for future reference, this is how to access the Transport struct: 44 //tlsconfig := lrt.Rt.(*http.Transport).TLSClientConfig 45 46 var err error 47 48 if lrt.OsDebug { 49 log.Printf("[DEBUG] OpenStack Request URL: %s %s", request.Method, request.URL) 50 log.Printf("[DEBUG] Openstack Request Headers:\n%s", FormatHeaders(request.Header, "\n")) 51 52 if request.Body != nil { 53 request.Body, err = lrt.logRequest(request.Body, request.Header.Get("Content-Type")) 54 if err != nil { 55 return nil, err 56 } 57 } 58 } 59 60 response, err := lrt.Rt.RoundTrip(request) 61 if response == nil { 62 return nil, err 63 } 64 65 if lrt.OsDebug { 66 log.Printf("[DEBUG] Openstack Response Code: %d", response.StatusCode) 67 log.Printf("[DEBUG] Openstack Response Headers:\n%s", FormatHeaders(response.Header, "\n")) 68 69 response.Body, err = lrt.logResponse(response.Body, response.Header.Get("Content-Type")) 70 } 71 72 return response, err 73 } 74 75 // logRequest will log the HTTP Request details. 76 // If the body is JSON, it will attempt to be pretty-formatted. 77 func (lrt *LogRoundTripper) logRequest(original io.ReadCloser, contentType string) (io.ReadCloser, error) { 78 defer original.Close() 79 80 var bs bytes.Buffer 81 _, err := io.Copy(&bs, original) 82 if err != nil { 83 return nil, err 84 } 85 86 // Handle request contentType 87 if strings.HasPrefix(contentType, "application/json") { 88 debugInfo := lrt.formatJSON(bs.Bytes()) 89 log.Printf("[DEBUG] OpenStack Request Body: %s", debugInfo) 90 } else { 91 log.Printf("[DEBUG] OpenStack Request Body: %s", bs.String()) 92 } 93 94 return ioutil.NopCloser(strings.NewReader(bs.String())), nil 95 } 96 97 // logResponse will log the HTTP Response details. 98 // If the body is JSON, it will attempt to be pretty-formatted. 99 func (lrt *LogRoundTripper) logResponse(original io.ReadCloser, contentType string) (io.ReadCloser, error) { 100 if strings.HasPrefix(contentType, "application/json") { 101 var bs bytes.Buffer 102 defer original.Close() 103 _, err := io.Copy(&bs, original) 104 if err != nil { 105 return nil, err 106 } 107 debugInfo := lrt.formatJSON(bs.Bytes()) 108 if debugInfo != "" { 109 log.Printf("[DEBUG] OpenStack Response Body: %s", debugInfo) 110 } 111 return ioutil.NopCloser(strings.NewReader(bs.String())), nil 112 } 113 114 log.Printf("[DEBUG] Not logging because OpenStack response body isn't JSON") 115 return original, nil 116 } 117 118 // formatJSON will try to pretty-format a JSON body. 119 // It will also mask known fields which contain sensitive information. 120 func (lrt *LogRoundTripper) formatJSON(raw []byte) string { 121 var data map[string]interface{} 122 123 err := json.Unmarshal(raw, &data) 124 if err != nil { 125 log.Printf("[DEBUG] Unable to parse OpenStack JSON: %s", err) 126 return string(raw) 127 } 128 129 // Mask known password fields 130 if v, ok := data["auth"].(map[string]interface{}); ok { 131 if v, ok := v["identity"].(map[string]interface{}); ok { 132 if v, ok := v["password"].(map[string]interface{}); ok { 133 if v, ok := v["user"].(map[string]interface{}); ok { 134 v["password"] = "***" 135 } 136 } 137 } 138 } 139 140 // Ignore the catalog 141 if v, ok := data["token"].(map[string]interface{}); ok { 142 if _, ok := v["catalog"]; ok { 143 return "" 144 } 145 } 146 147 pretty, err := json.MarshalIndent(data, "", " ") 148 if err != nil { 149 log.Printf("[DEBUG] Unable to re-marshal OpenStack JSON: %s", err) 150 return string(raw) 151 } 152 153 return string(pretty) 154 } 155 156 // Firewall is an OpenStack firewall. 157 type Firewall struct { 158 firewalls.Firewall 159 routerinsertion.FirewallExt 160 } 161 162 // FirewallCreateOpts represents the attributes used when creating a new firewall. 163 type FirewallCreateOpts struct { 164 firewalls.CreateOptsBuilder 165 ValueSpecs map[string]string `json:"value_specs,omitempty"` 166 } 167 168 // ToFirewallCreateMap casts a CreateOptsExt struct to a map. 169 // It overrides firewalls.ToFirewallCreateMap to add the ValueSpecs field. 170 func (opts FirewallCreateOpts) ToFirewallCreateMap() (map[string]interface{}, error) { 171 body, err := opts.CreateOptsBuilder.ToFirewallCreateMap() 172 if err != nil { 173 return nil, err 174 } 175 176 return AddValueSpecs(body), nil 177 } 178 179 //FirewallUpdateOpts 180 type FirewallUpdateOpts struct { 181 firewalls.UpdateOptsBuilder 182 } 183 184 func (opts FirewallUpdateOpts) ToFirewallUpdateMap() (map[string]interface{}, error) { 185 return BuildRequest(opts, "firewall") 186 } 187 188 // FloatingIPCreateOpts represents the attributes used when creating a new floating ip. 189 type FloatingIPCreateOpts struct { 190 floatingips.CreateOpts 191 ValueSpecs map[string]string `json:"value_specs,omitempty"` 192 } 193 194 // ToFloatingIPCreateMap casts a CreateOpts struct to a map. 195 // It overrides floatingips.ToFloatingIPCreateMap to add the ValueSpecs field. 196 func (opts FloatingIPCreateOpts) ToFloatingIPCreateMap() (map[string]interface{}, error) { 197 return BuildRequest(opts, "floatingip") 198 } 199 200 // KeyPairCreateOpts represents the attributes used when creating a new keypair. 201 type KeyPairCreateOpts struct { 202 keypairs.CreateOpts 203 ValueSpecs map[string]string `json:"value_specs,omitempty"` 204 } 205 206 // ToKeyPairCreateMap casts a CreateOpts struct to a map. 207 // It overrides keypairs.ToKeyPairCreateMap to add the ValueSpecs field. 208 func (opts KeyPairCreateOpts) ToKeyPairCreateMap() (map[string]interface{}, error) { 209 return BuildRequest(opts, "keypair") 210 } 211 212 // NetworkCreateOpts represents the attributes used when creating a new network. 213 type NetworkCreateOpts struct { 214 networks.CreateOpts 215 ValueSpecs map[string]string `json:"value_specs,omitempty"` 216 } 217 218 // ToNetworkCreateMap casts a CreateOpts struct to a map. 219 // It overrides networks.ToNetworkCreateMap to add the ValueSpecs field. 220 func (opts NetworkCreateOpts) ToNetworkCreateMap() (map[string]interface{}, error) { 221 return BuildRequest(opts, "network") 222 } 223 224 // PolicyCreateOpts represents the attributes used when creating a new firewall policy. 225 type PolicyCreateOpts struct { 226 policies.CreateOpts 227 ValueSpecs map[string]string `json:"value_specs,omitempty"` 228 } 229 230 // ToPolicyCreateMap casts a CreateOpts struct to a map. 231 // It overrides policies.ToFirewallPolicyCreateMap to add the ValueSpecs field. 232 func (opts PolicyCreateOpts) ToFirewallPolicyCreateMap() (map[string]interface{}, error) { 233 return BuildRequest(opts, "firewall_policy") 234 } 235 236 // PortCreateOpts represents the attributes used when creating a new port. 237 type PortCreateOpts struct { 238 ports.CreateOpts 239 ValueSpecs map[string]string `json:"value_specs,omitempty"` 240 } 241 242 // ToPortCreateMap casts a CreateOpts struct to a map. 243 // It overrides ports.ToPortCreateMap to add the ValueSpecs field. 244 func (opts PortCreateOpts) ToPortCreateMap() (map[string]interface{}, error) { 245 return BuildRequest(opts, "port") 246 } 247 248 // RecordSetCreateOpts represents the attributes used when creating a new DNS record set. 249 type RecordSetCreateOpts struct { 250 recordsets.CreateOpts 251 ValueSpecs map[string]string `json:"value_specs,omitempty"` 252 } 253 254 // ToRecordSetCreateMap casts a CreateOpts struct to a map. 255 // It overrides recordsets.ToRecordSetCreateMap to add the ValueSpecs field. 256 func (opts RecordSetCreateOpts) ToRecordSetCreateMap() (map[string]interface{}, error) { 257 b, err := BuildRequest(opts, "") 258 if err != nil { 259 return nil, err 260 } 261 262 if m, ok := b[""].(map[string]interface{}); ok { 263 return m, nil 264 } 265 266 return nil, fmt.Errorf("Expected map but got %T", b[""]) 267 } 268 269 // RouterCreateOpts represents the attributes used when creating a new router. 270 type RouterCreateOpts struct { 271 routers.CreateOpts 272 ValueSpecs map[string]string `json:"value_specs,omitempty"` 273 } 274 275 // ToRouterCreateMap casts a CreateOpts struct to a map. 276 // It overrides routers.ToRouterCreateMap to add the ValueSpecs field. 277 func (opts RouterCreateOpts) ToRouterCreateMap() (map[string]interface{}, error) { 278 return BuildRequest(opts, "router") 279 } 280 281 // RuleCreateOpts represents the attributes used when creating a new firewall rule. 282 type RuleCreateOpts struct { 283 rules.CreateOpts 284 ValueSpecs map[string]string `json:"value_specs,omitempty"` 285 } 286 287 // ToRuleCreateMap casts a CreateOpts struct to a map. 288 // It overrides rules.ToRuleCreateMap to add the ValueSpecs field. 289 func (opts RuleCreateOpts) ToRuleCreateMap() (map[string]interface{}, error) { 290 b, err := BuildRequest(opts, "firewall_rule") 291 if err != nil { 292 return nil, err 293 } 294 295 if m := b["firewall_rule"].(map[string]interface{}); m["protocol"] == "any" { 296 m["protocol"] = nil 297 } 298 299 return b, nil 300 } 301 302 // ServerGroupCreateOpts represents the attributes used when creating a new router. 303 type ServerGroupCreateOpts struct { 304 servergroups.CreateOpts 305 ValueSpecs map[string]string `json:"value_specs,omitempty"` 306 } 307 308 // ToServerGroupCreateMap casts a CreateOpts struct to a map. 309 // It overrides routers.ToServerGroupCreateMap to add the ValueSpecs field. 310 func (opts ServerGroupCreateOpts) ToServerGroupCreateMap() (map[string]interface{}, error) { 311 return BuildRequest(opts, "server_group") 312 } 313 314 // SubnetCreateOpts represents the attributes used when creating a new subnet. 315 type SubnetCreateOpts struct { 316 subnets.CreateOpts 317 ValueSpecs map[string]string `json:"value_specs,omitempty"` 318 } 319 320 // ToSubnetCreateMap casts a CreateOpts struct to a map. 321 // It overrides subnets.ToSubnetCreateMap to add the ValueSpecs field. 322 func (opts SubnetCreateOpts) ToSubnetCreateMap() (map[string]interface{}, error) { 323 b, err := BuildRequest(opts, "subnet") 324 if err != nil { 325 return nil, err 326 } 327 328 if m := b["subnet"].(map[string]interface{}); m["gateway_ip"] == "" { 329 m["gateway_ip"] = nil 330 } 331 332 return b, nil 333 } 334 335 // ZoneCreateOpts represents the attributes used when creating a new DNS zone. 336 type ZoneCreateOpts struct { 337 zones.CreateOpts 338 ValueSpecs map[string]string `json:"value_specs,omitempty"` 339 } 340 341 // ToZoneCreateMap casts a CreateOpts struct to a map. 342 // It overrides zones.ToZoneCreateMap to add the ValueSpecs field. 343 func (opts ZoneCreateOpts) ToZoneCreateMap() (map[string]interface{}, error) { 344 b, err := BuildRequest(opts, "") 345 if err != nil { 346 return nil, err 347 } 348 349 if m, ok := b[""].(map[string]interface{}); ok { 350 if opts.TTL > 0 { 351 m["ttl"] = opts.TTL 352 } 353 354 return m, nil 355 } 356 357 return nil, fmt.Errorf("Expected map but got %T", b[""]) 358 }