github.com/cbroglie/terraform@v0.7.0-rc3.0.20170410193827-735dfc416d46/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.logRequestBody(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.logResponseBody(response.Body, response.Header) 62 } 63 64 return response, err 65 } 66 67 // logRequestBody will log the HTTP Request body. 68 // If the body is JSON, it will attempt to be pretty-formatted. 69 func (lrt *LogRoundTripper) logRequestBody(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 contentType := headers.Get("Content-Type") 79 if strings.HasPrefix(contentType, "application/json") { 80 debugInfo := lrt.formatJSON(bs.Bytes()) 81 log.Printf("[DEBUG] OpenStack Request Options: %s", debugInfo) 82 } else { 83 log.Printf("[DEBUG] OpenStack Request Options: %s", bs.String()) 84 } 85 86 return ioutil.NopCloser(strings.NewReader(bs.String())), nil 87 } 88 89 // logResponseBody will log the HTTP Response body. 90 // If the body is JSON, it will attempt to be pretty-formatted. 91 func (lrt *LogRoundTripper) logResponseBody(original io.ReadCloser, headers http.Header) (io.ReadCloser, error) { 92 contentType := headers.Get("Content-Type") 93 if strings.HasPrefix(contentType, "application/json") { 94 var bs bytes.Buffer 95 defer original.Close() 96 _, err := io.Copy(&bs, original) 97 if err != nil { 98 return nil, err 99 } 100 debugInfo := lrt.formatJSON(bs.Bytes()) 101 if debugInfo != "" { 102 log.Printf("[DEBUG] OpenStack Response Body: %s", debugInfo) 103 } 104 return ioutil.NopCloser(strings.NewReader(bs.String())), nil 105 } 106 107 log.Printf("[DEBUG] Not logging because OpenStack response body isn't JSON") 108 return original, nil 109 } 110 111 // formatJSON will try to pretty-format a JSON body. 112 // It will also mask known fields which contain sensitive information. 113 func (lrt *LogRoundTripper) formatJSON(raw []byte) string { 114 var data map[string]interface{} 115 116 err := json.Unmarshal(raw, &data) 117 if err != nil { 118 log.Printf("[DEBUG] Unable to parse OpenStack JSON: %s", err) 119 return string(raw) 120 } 121 122 // Mask known password fields 123 if v, ok := data["auth"].(map[string]interface{}); ok { 124 if v, ok := v["identity"].(map[string]interface{}); ok { 125 if v, ok := v["password"].(map[string]interface{}); ok { 126 if v, ok := v["user"].(map[string]interface{}); ok { 127 v["password"] = "***" 128 } 129 } 130 } 131 } 132 133 // Ignore the catalog 134 if v, ok := data["token"].(map[string]interface{}); ok { 135 if _, ok := v["catalog"]; ok { 136 return "" 137 } 138 } 139 140 pretty, err := json.MarshalIndent(data, "", " ") 141 if err != nil { 142 log.Printf("[DEBUG] Unable to re-marshal OpenStack JSON: %s", err) 143 return string(raw) 144 } 145 146 return string(pretty) 147 } 148 149 // FirewallCreateOpts represents the attributes used when creating a new firewall. 150 type FirewallCreateOpts struct { 151 firewalls.CreateOpts 152 ValueSpecs map[string]string `json:"value_specs,omitempty"` 153 } 154 155 // ToFirewallCreateMap casts a CreateOpts struct to a map. 156 // It overrides firewalls.ToFirewallCreateMap to add the ValueSpecs field. 157 func (opts FirewallCreateOpts) ToFirewallCreateMap() (map[string]interface{}, error) { 158 return BuildRequest(opts, "firewall") 159 } 160 161 // FloatingIPCreateOpts represents the attributes used when creating a new floating ip. 162 type FloatingIPCreateOpts struct { 163 floatingips.CreateOpts 164 ValueSpecs map[string]string `json:"value_specs,omitempty"` 165 } 166 167 // ToFloatingIPCreateMap casts a CreateOpts struct to a map. 168 // It overrides floatingips.ToFloatingIPCreateMap to add the ValueSpecs field. 169 func (opts FloatingIPCreateOpts) ToFloatingIPCreateMap() (map[string]interface{}, error) { 170 return BuildRequest(opts, "floatingip") 171 } 172 173 // KeyPairCreateOpts represents the attributes used when creating a new keypair. 174 type KeyPairCreateOpts struct { 175 keypairs.CreateOpts 176 ValueSpecs map[string]string `json:"value_specs,omitempty"` 177 } 178 179 // ToKeyPairCreateMap casts a CreateOpts struct to a map. 180 // It overrides keypairs.ToKeyPairCreateMap to add the ValueSpecs field. 181 func (opts KeyPairCreateOpts) ToKeyPairCreateMap() (map[string]interface{}, error) { 182 return BuildRequest(opts, "keypair") 183 } 184 185 // NetworkCreateOpts represents the attributes used when creating a new network. 186 type NetworkCreateOpts struct { 187 networks.CreateOpts 188 ValueSpecs map[string]string `json:"value_specs,omitempty"` 189 } 190 191 // ToNetworkCreateMap casts a CreateOpts struct to a map. 192 // It overrides networks.ToNetworkCreateMap to add the ValueSpecs field. 193 func (opts NetworkCreateOpts) ToNetworkCreateMap() (map[string]interface{}, error) { 194 return BuildRequest(opts, "network") 195 } 196 197 // PolicyCreateOpts represents the attributes used when creating a new firewall policy. 198 type PolicyCreateOpts struct { 199 policies.CreateOpts 200 ValueSpecs map[string]string `json:"value_specs,omitempty"` 201 } 202 203 // ToPolicyCreateMap casts a CreateOpts struct to a map. 204 // It overrides policies.ToFirewallPolicyCreateMap to add the ValueSpecs field. 205 func (opts PolicyCreateOpts) ToFirewallPolicyCreateMap() (map[string]interface{}, error) { 206 return BuildRequest(opts, "firewall_policy") 207 } 208 209 // PortCreateOpts represents the attributes used when creating a new port. 210 type PortCreateOpts struct { 211 ports.CreateOpts 212 ValueSpecs map[string]string `json:"value_specs,omitempty"` 213 } 214 215 // ToPortCreateMap casts a CreateOpts struct to a map. 216 // It overrides ports.ToPortCreateMap to add the ValueSpecs field. 217 func (opts PortCreateOpts) ToPortCreateMap() (map[string]interface{}, error) { 218 return BuildRequest(opts, "port") 219 } 220 221 // RouterCreateOpts represents the attributes used when creating a new router. 222 type RouterCreateOpts struct { 223 routers.CreateOpts 224 ValueSpecs map[string]string `json:"value_specs,omitempty"` 225 } 226 227 // ToRouterCreateMap casts a CreateOpts struct to a map. 228 // It overrides routers.ToRouterCreateMap to add the ValueSpecs field. 229 func (opts RouterCreateOpts) ToRouterCreateMap() (map[string]interface{}, error) { 230 return BuildRequest(opts, "router") 231 } 232 233 // RuleCreateOpts represents the attributes used when creating a new firewall rule. 234 type RuleCreateOpts struct { 235 rules.CreateOpts 236 ValueSpecs map[string]string `json:"value_specs,omitempty"` 237 } 238 239 // ToRuleCreateMap casts a CreateOpts struct to a map. 240 // It overrides rules.ToRuleCreateMap to add the ValueSpecs field. 241 func (opts RuleCreateOpts) ToRuleCreateMap() (map[string]interface{}, error) { 242 b, err := BuildRequest(opts, "firewall_rule") 243 if err != nil { 244 return nil, err 245 } 246 247 if m := b["firewall_rule"].(map[string]interface{}); m["protocol"] == "any" { 248 m["protocol"] = nil 249 } 250 251 return b, nil 252 } 253 254 // ServerGroupCreateOpts represents the attributes used when creating a new router. 255 type ServerGroupCreateOpts struct { 256 servergroups.CreateOpts 257 ValueSpecs map[string]string `json:"value_specs,omitempty"` 258 } 259 260 // ToServerGroupCreateMap casts a CreateOpts struct to a map. 261 // It overrides routers.ToServerGroupCreateMap to add the ValueSpecs field. 262 func (opts ServerGroupCreateOpts) ToServerGroupCreateMap() (map[string]interface{}, error) { 263 return BuildRequest(opts, "server_group") 264 } 265 266 // SubnetCreateOpts represents the attributes used when creating a new subnet. 267 type SubnetCreateOpts struct { 268 subnets.CreateOpts 269 ValueSpecs map[string]string `json:"value_specs,omitempty"` 270 } 271 272 // ToSubnetCreateMap casts a CreateOpts struct to a map. 273 // It overrides subnets.ToSubnetCreateMap to add the ValueSpecs field. 274 func (opts SubnetCreateOpts) ToSubnetCreateMap() (map[string]interface{}, error) { 275 b, err := BuildRequest(opts, "subnet") 276 if err != nil { 277 return nil, err 278 } 279 280 if m := b["subnet"].(map[string]interface{}); m["gateway_ip"] == "" { 281 m["gateway_ip"] = nil 282 } 283 284 return b, nil 285 }