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