Ejemplo n.º 1
0
func (r *Route53) query(method, path string, req, resp interface{}) error {
	params := make(map[string]string)
	endpoint, err := url.Parse(r.Region.Route53Endpoint)
	if err != nil {
		return err
	}
	endpoint.Path = path
	sign(r.Auth, endpoint.Path, params)

	// If they look like url.Values, just encode...
	if queryArgs, ok := req.(url.Values); ok {
		endpoint.RawQuery = queryArgs.Encode()
		req = nil
	}

	// Encode the body
	var body io.ReadWriter
	if req != nil {
		bodyBuf := bytes.NewBuffer(nil)
		enc := xml.NewEncoder(bodyBuf)
		start := xml.StartElement{
			Name: xml.Name{
				Space: "",
				Local: reflect.Indirect(reflect.ValueOf(req)).Type().Name(),
			},
			Attr: []xml.Attr{{xml.Name{"", "xmlns"}, "https://route53.amazonaws.com/doc/2013-04-01/"}},
		}
		if err := enc.EncodeElement(req, start); err != nil {
			return err
		}

		// This is really a sadness, but can't think of a better way to
		// do this for now in Go's constructs.
		replace := "<ResourceRecords><ResourceRecord></ResourceRecord></ResourceRecords>"
		if strings.Contains(bodyBuf.String(), replace) {
			var newBuf bytes.Buffer
			newBuf.WriteString(strings.Replace(bodyBuf.String(), replace, "", -1))
			bodyBuf = &newBuf
		}

		// http://docs.aws.amazon.com/Route53/latest/APIReference/CreateAliasRRSAPI.html
		if reflect.Indirect(reflect.ValueOf(req)).Type().Name() == "ChangeResourceRecordSetsRequest" {
			for _, change := range req.(ChangeResourceRecordSetsRequest).Changes {
				if change.Record.AliasTarget != nil {
					replace := change.Record.Type + "</Type><TTL>0</TTL>"
					var newBuf bytes.Buffer
					newBuf.WriteString(strings.Replace(bodyBuf.String(), replace, change.Record.Type+"</Type>", -1))
					bodyBuf = &newBuf
				}
			}
		}

		body = bodyBuf
	}

	// Make the http request
	hReq, err := http.NewRequest(method, endpoint.String(), body)
	if err != nil {
		return err
	}
	for k, v := range params {
		hReq.Header.Set(k, v)
	}
	re, err := r.httpClient.Do(hReq)
	if err != nil {
		return err
	}
	defer re.Body.Close()

	// Check the status code
	switch re.StatusCode {
	case 200:
	case 201:
	default:
		var body bytes.Buffer
		io.Copy(&body, re.Body)
		return fmt.Errorf("Request failed, got status code: %d. Response: %s",
			re.StatusCode, body.Bytes())
	}

	// Decode the response
	decoder := xml.NewDecoder(re.Body)
	return decoder.Decode(resp)
}