You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

255 lines
7.1 KiB

  1. package route53
  2. import (
  3. "bytes"
  4. "encoding/xml"
  5. "fmt"
  6. "github.com/goamz/goamz/aws"
  7. "io"
  8. "net/http"
  9. )
  10. type Route53 struct {
  11. Auth aws.Auth
  12. Endpoint string
  13. Signer *aws.Route53Signer
  14. Service *aws.Service
  15. }
  16. const route53_host = "https://route53.amazonaws.com"
  17. // Factory for the route53 type
  18. func NewRoute53(auth aws.Auth) (*Route53, error) {
  19. signer := aws.NewRoute53Signer(auth)
  20. return &Route53{
  21. Auth: auth,
  22. Signer: signer,
  23. Endpoint: route53_host + "/2013-04-01/hostedzone",
  24. }, nil
  25. }
  26. // General Structs used in all types of requests
  27. type HostedZone struct {
  28. XMLName xml.Name `xml:"HostedZone"`
  29. Id string
  30. Name string
  31. CallerReference string
  32. Config Config
  33. ResourceRecordSetCount int
  34. }
  35. type Config struct {
  36. XMLName xml.Name `xml:"Config"`
  37. Comment string
  38. }
  39. // Structs for getting the existing Hosted Zones
  40. type ListHostedZonesResponse struct {
  41. XMLName xml.Name `xml:"ListHostedZonesResponse"`
  42. HostedZones []HostedZone `xml:"HostedZones>HostedZone"`
  43. Marker string
  44. IsTruncated bool
  45. NextMarker string
  46. MaxItems int
  47. }
  48. // Structs for Creating a New Host
  49. type CreateHostedZoneRequest struct {
  50. XMLName xml.Name `xml:"CreateHostedZoneRequest"`
  51. Xmlns string `xml:"xmlns,attr"`
  52. Name string
  53. CallerReference string
  54. HostedZoneConfig HostedZoneConfig
  55. }
  56. type ResourceRecordValue struct {
  57. Value string `xml:"Value"`
  58. }
  59. type AliasTarget struct {
  60. HostedZoneId string `xml:"HostedZoneId"`
  61. DNSName string `xml:"DNSName"`
  62. EvaluateTargetHealth bool `xml:"EvaluateTargetHealth"`
  63. }
  64. // Wrapper for all the different resource record sets
  65. type ResourceRecordSet interface{}
  66. // Basic Change
  67. type Change struct {
  68. Action string `xml:"Action"`
  69. Name string `xml:"ResourceRecordSet>Name"`
  70. Type string `xml:"ResourceRecordSet>Type"`
  71. TTL int `xml:"ResourceRecordSet>TTL,omitempty"`
  72. Values []ResourceRecordValue `xml:"ResourceRecordSet>ResourceRecords>ResourceRecord"`
  73. HealthCheckId string `xml:"ResourceRecordSet>HealthCheckId,omitempty"`
  74. }
  75. // Basic Resource Recod Set
  76. type BasicResourceRecordSet struct {
  77. Action string `xml:"Action"`
  78. Name string `xml:"ResourceRecordSet>Name"`
  79. Type string `xml:"ResourceRecordSet>Type"`
  80. TTL int `xml:"ResourceRecordSet>TTL,omitempty"`
  81. Values []ResourceRecordValue `xml:"ResourceRecordSet>ResourceRecords>ResourceRecord"`
  82. HealthCheckId string `xml:"ResourceRecordSet>HealthCheckId,omitempty"`
  83. }
  84. // Alias Resource Record Set
  85. type AliasResourceRecordSet struct {
  86. Action string `xml:"Action"`
  87. Name string `xml:"ResourceRecordSet>Name"`
  88. Type string `xml:"ResourceRecordSet>Type"`
  89. AliasTarget AliasTarget `xml:"ResourceRecordSet>AliasTarget"`
  90. HealthCheckId string `xml:"ResourceRecordSet>HealthCheckId,omitempty"`
  91. }
  92. type ChangeResourceRecordSetsRequest struct {
  93. XMLName xml.Name `xml:"ChangeResourceRecordSetsRequest"`
  94. Xmlns string `xml:"xmlns,attr"`
  95. Changes []ResourceRecordSet `xml:"ChangeBatch>Changes>Change"`
  96. }
  97. type HostedZoneConfig struct {
  98. XMLName xml.Name `xml:"HostedZoneConfig"`
  99. Comment string
  100. }
  101. type CreateHostedZoneResponse struct {
  102. XMLName xml.Name `xml:"CreateHostedZoneResponse"`
  103. HostedZone HostedZone
  104. ChangeInfo ChangeInfo
  105. DelegationSet DelegationSet
  106. }
  107. type ChangeResourceRecordSetsResponse struct {
  108. XMLName xml.Name `xml:"ChangeResourceRecordSetsResponse"`
  109. Id string `xml:"ChangeInfo>Id"`
  110. Status string `xml:"ChangeInfo>Status"`
  111. SubmittedAt string `xml:"ChangeInfo>SubmittedAt"`
  112. }
  113. type ChangeInfo struct {
  114. XMLName xml.Name `xml:"ChangeInfo"`
  115. Id string
  116. Status string
  117. SubmittedAt string
  118. }
  119. type DelegationSet struct {
  120. XMLName xml.Name `xml:"DelegationSet`
  121. NameServers NameServers
  122. }
  123. type NameServers struct {
  124. XMLName xml.Name `xml:"NameServers`
  125. NameServer []string
  126. }
  127. type GetHostedZoneResponse struct {
  128. XMLName xml.Name `xml:"GetHostedZoneResponse"`
  129. HostedZone HostedZone
  130. DelegationSet DelegationSet
  131. }
  132. type DeleteHostedZoneResponse struct {
  133. XMLName xml.Name `xml:"DeleteHostedZoneResponse"`
  134. Xmlns string `xml:"xmlns,attr"`
  135. ChangeInfo ChangeInfo
  136. }
  137. // query sends the specified HTTP request to the path and signs the request
  138. // with the required authentication and headers based on the Auth.
  139. //
  140. // Automatically decodes the response into the the result interface
  141. func (r *Route53) query(method string, path string, body io.Reader, result interface{}) error {
  142. var err error
  143. // Create the POST request and sign the headers
  144. req, err := http.NewRequest(method, path, body)
  145. r.Signer.Sign(req)
  146. // Send the request and capture the response
  147. client := &http.Client{}
  148. res, err := client.Do(req)
  149. if err != nil {
  150. return err
  151. }
  152. if method == "POST" {
  153. defer req.Body.Close()
  154. }
  155. if res.StatusCode != 201 && res.StatusCode != 200 {
  156. err = r.Service.BuildError(res)
  157. return err
  158. }
  159. err = xml.NewDecoder(res.Body).Decode(result)
  160. return err
  161. }
  162. // CreateHostedZone send a creation request to the AWS Route53 API
  163. func (r *Route53) CreateHostedZone(hostedZoneReq *CreateHostedZoneRequest) (*CreateHostedZoneResponse, error) {
  164. xmlBytes, err := xml.Marshal(hostedZoneReq)
  165. if err != nil {
  166. return nil, err
  167. }
  168. result := new(CreateHostedZoneResponse)
  169. err = r.query("POST", r.Endpoint, bytes.NewBuffer(xmlBytes), result)
  170. return result, err
  171. }
  172. // ChangeResourceRecordSet send a change resource record request to the AWS Route53 API
  173. func (r *Route53) ChangeResourceRecordSet(req *ChangeResourceRecordSetsRequest, zoneId string) (*ChangeResourceRecordSetsResponse, error) {
  174. xmlBytes, err := xml.Marshal(req)
  175. if err != nil {
  176. return nil, err
  177. }
  178. xmlBytes = []byte(xml.Header + string(xmlBytes))
  179. result := new(ChangeResourceRecordSetsResponse)
  180. path := fmt.Sprintf("%s/%s/rrset", r.Endpoint, zoneId)
  181. err = r.query("POST", path, bytes.NewBuffer(xmlBytes), result)
  182. return result, err
  183. }
  184. // ListedHostedZones fetches a collection of HostedZones through the AWS Route53 API
  185. func (r *Route53) ListHostedZones(marker string, maxItems int) (result *ListHostedZonesResponse, err error) {
  186. path := ""
  187. if marker == "" {
  188. path = fmt.Sprintf("%s?maxitems=%d", r.Endpoint, maxItems)
  189. } else {
  190. path = fmt.Sprintf("%s?marker=%v&maxitems=%d", r.Endpoint, marker, maxItems)
  191. }
  192. result = new(ListHostedZonesResponse)
  193. err = r.query("GET", path, nil, result)
  194. return
  195. }
  196. // GetHostedZone fetches a particular hostedzones DelegationSet by id
  197. func (r *Route53) GetHostedZone(id string) (result *GetHostedZoneResponse, err error) {
  198. result = new(GetHostedZoneResponse)
  199. err = r.query("GET", fmt.Sprintf("%s/%v", r.Endpoint, id), nil, result)
  200. return
  201. }
  202. // DeleteHostedZone deletes the hosted zone with the given id
  203. func (r *Route53) DeleteHostedZone(id string) (result *DeleteHostedZoneResponse, err error) {
  204. path := fmt.Sprintf("%s/%s", r.Endpoint, id)
  205. result = new(DeleteHostedZoneResponse)
  206. err = r.query("DELETE", path, nil, result)
  207. return
  208. }