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  }