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