File: route53.go

package info (click to toggle)
golang-github-docker-goamz 0.0~git20160206.0.f0a21f5-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 1,580 kB
  • sloc: makefile: 66
file content (369 lines) | stat: -rw-r--r-- 10,929 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
package route53

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"github.com/docker/goamz/aws"
	"io"
	"net/http"
	"strconv"
)

type Route53 struct {
	Auth     aws.Auth
	Endpoint string
	Signer   *aws.Route53Signer
	Service  *aws.Service
}

const route53_host = "https://route53.amazonaws.com"

// Factory for the route53 type
func NewRoute53(auth aws.Auth) (*Route53, error) {
	signer := aws.NewRoute53Signer(auth)

	return &Route53{
		Auth:     auth,
		Signer:   signer,
		Endpoint: route53_host + "/2013-04-01/hostedzone",
	}, nil
}

// General Structs used in all types of requests
type HostedZone struct {
	XMLName                xml.Name `xml:"HostedZone"`
	Id                     string
	Name                   string
	VPC                    HostedZoneVPC `xml:"VPC,omitempty"` // used on CreateHostedZone
	CallerReference        string
	Config                 Config
	ResourceRecordSetCount int
}

type Config struct {
	XMLName     xml.Name `xml:"Config"`
	Comment     string
	PrivateZone bool
}

// Structs for getting the existing Hosted Zones
type ListHostedZonesResponse struct {
	XMLName     xml.Name     `xml:"https://route53.amazonaws.com/doc/2013-04-01/ ListHostedZonesResponse"`
	HostedZones []HostedZone `xml:"HostedZones>HostedZone"`
	Marker      string
	IsTruncated bool
	NextMarker  string
	MaxItems    int
}

// Structs for Creating a New Host
type CreateHostedZoneRequest struct {
	XMLName          xml.Name `xml:"https://route53.amazonaws.com/doc/2013-04-01/ CreateHostedZoneRequest"`
	Name             string
	CallerReference  string
	VPC              HostedZoneVPC
	HostedZoneConfig HostedZoneConfig
}

type ResourceRecordValue struct {
	Value string `xml:"ResourceRecord>Value"`
}

type Change struct {
	Action      string                `xml:"Action"`
	Name        string                `xml:"ResourceRecordSet>Name"`
	Type        string                `xml:"ResourceRecordSet>Type"`
	TTL         int                   `xml:"ResourceRecordSet>TTL,omitempty"`
	AliasTarget *AliasTarget          `xml:"ResourceRecordSet>AliasTarget,omitempty"`
	Values      []ResourceRecordValue `xml:"ResourceRecordSet>ResourceRecords,omitempty"`
}

type ChangeResourceRecordSetsRequest struct {
	XMLName xml.Name `xml:"https://route53.amazonaws.com/doc/2013-04-01/ ChangeResourceRecordSetsRequest"`
	Changes []Change `xml:"ChangeBatch>Changes>Change"`
}

type AssociateVPCWithHostedZoneRequest struct {
	XMLName xml.Name `xml:"https://route53.amazonaws.com/doc/2013-04-01/ AssociateVPCWithHostedZoneRequest"`
	VPC     HostedZoneVPC
	Comment string
}

type DisassociateVPCWithHostedZoneRequest struct {
	XMLName xml.Name `xml:"https://route53.amazonaws.com/doc/2013-04-01/ DisassociateVPCWithHostedZoneRequest"`
	VPC     HostedZoneVPC
	Comment string
}

type HostedZoneConfig struct {
	XMLName xml.Name `xml:"HostedZoneConfig"`
	Comment string
}

type HostedZoneVPC struct {
	XMLName   xml.Name `xml:"VPC"`
	VPCId     string
	VPCRegion string
}

type CreateHostedZoneResponse struct {
	XMLName       xml.Name `xml:"https://route53.amazonaws.com/doc/2013-04-01/ CreateHostedZoneResponse"`
	HostedZone    HostedZone
	ChangeInfo    ChangeInfo
	DelegationSet DelegationSet
}

type AliasTarget struct {
	HostedZoneId         string
	DNSName              string
	EvaluateTargetHealth bool
}

type ResourceRecord struct {
	XMLName xml.Name `xml:"ResourceRecord"`
	Value   string
}

type ResourceRecords struct {
	XMLName        xml.Name `xml:"ResourceRecords"`
	ResourceRecord []ResourceRecord
}

type ResourceRecordSet struct {
	XMLName         xml.Name `xml:"ResourceRecordSet"`
	Name            string
	Type            string
	TTL             int
	ResourceRecords []ResourceRecords
	HealthCheckId   string
	Region          string
	Failover        string
	AliasTarget     AliasTarget
}

type ResourceRecordSets struct {
	XMLName           xml.Name `xml:"ResourceRecordSets"`
	ResourceRecordSet []ResourceRecordSet
}

type ListResourceRecordSetsResponse struct {
	XMLName              xml.Name `xml:"https://route53.amazonaws.com/doc/2013-04-01/ ListResourceRecordSetsResponse"`
	ResourceRecordSets   []ResourceRecordSets
	IsTruncated          bool
	MaxItems             int
	NextRecordName       string
	NextRecordType       string
	NextRecordIdentifier string
}

type ChangeResourceRecordSetsResponse struct {
	XMLName     xml.Name `xml:"https://route53.amazonaws.com/doc/2013-04-01/ ChangeResourceRecordSetsResponse"`
	Id          string   `xml:"ChangeInfo>Id"`
	Status      string   `xml:"ChangeInfo>Status"`
	SubmittedAt string   `xml:"ChangeInfo>SubmittedAt"`
}

type ChangeInfo struct {
	XMLName     xml.Name `xml:"ChangeInfo"`
	Id          string
	Status      string
	SubmittedAt string
}

type DelegationSet struct {
	XMLName     xml.Name `xml:"DelegationSet"`
	NameServers NameServers
}

type NameServers struct {
	XMLName    xml.Name `xml:"NameServers"`
	NameServer []string
}

type GetHostedZoneResponse struct {
	XMLName       xml.Name `xml:"https://route53.amazonaws.com/doc/2013-04-01/ GetHostedZoneResponse"`
	HostedZone    HostedZone
	DelegationSet DelegationSet
	VPCs          []HostedZoneVPC `xml:"VPCs>VPC"`
}

type DeleteHostedZoneResponse struct {
	XMLName    xml.Name `xml:"https://route53.amazonaws.com/doc/2013-04-01/ DeleteHostedZoneResponse"`
	ChangeInfo ChangeInfo
}

type AssociateVPCWithHostedZoneResponse struct {
	XMLName    xml.Name `xml:"https://route53.amazonaws.com/doc/2013-04-01/ AssociateVPCWithHostedZoneResponse"`
	ChangeInfo ChangeInfo
}

type DisassociateVPCWithHostedZoneResponse struct {
	XMLName    xml.Name `xml:"https://route53.amazonaws.com/doc/2013-04-01/ DisassociateVPCWithHostedZoneResponse"`
	ChangeInfo ChangeInfo
}

// query sends the specified HTTP request to the path and signs the request
// with the required authentication and headers based on the Auth.
//
// Automatically decodes the response into the the result interface
func (r *Route53) query(method string, path string, body io.Reader, result interface{}) error {
	var err error

	// Create the POST request and sign the headers
	req, err := http.NewRequest(method, path, body)
	r.Signer.Sign(req)

	// Send the request and capture the response
	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		return err
	}

	if method == "POST" {
		defer req.Body.Close()
	}

	if res.StatusCode != 201 && res.StatusCode != 200 {
		err = r.Service.BuildError(res)
		return err
	}

	err = xml.NewDecoder(res.Body).Decode(result)

	return err
}

// CreateHostedZone send a creation request to the AWS Route53 API
func (r *Route53) CreateHostedZone(hostedZoneReq *CreateHostedZoneRequest) (*CreateHostedZoneResponse, error) {
	xmlBytes, err := xml.Marshal(hostedZoneReq)
	if err != nil {
		return nil, err
	}

	result := new(CreateHostedZoneResponse)
	err = r.query("POST", r.Endpoint, bytes.NewBuffer(xmlBytes), result)

	return result, err
}

// ListResourceRecordSets fetches a collection of ResourceRecordSets through the AWS Route53 API
func (r *Route53) ListResourceRecordSets(hostedZone string, name string, _type string, identifier string, maxitems int) (result *ListResourceRecordSetsResponse, err error) {
	var buffer bytes.Buffer
	addParam(&buffer, "name", name)
	addParam(&buffer, "type", _type)
	addParam(&buffer, "identifier", identifier)
	if maxitems > 0 {
		addParam(&buffer, "maxitems", strconv.Itoa(maxitems))
	}
	path := fmt.Sprintf("%s/%s/rrset?%s", r.Endpoint, hostedZone, buffer.String())

	result = new(ListResourceRecordSetsResponse)
	err = r.query("GET", path, nil, result)

	return
}

func (response *ListResourceRecordSetsResponse) GetResourceRecordSets() []ResourceRecordSet {
	return response.ResourceRecordSets[0].ResourceRecordSet
}

func (recordset *ResourceRecordSet) GetValues() []string {
	if len(recordset.ResourceRecords) > 0 {
		result := make([]string, len(recordset.ResourceRecords[0].ResourceRecord))
		for i, record := range recordset.ResourceRecords[0].ResourceRecord {
			result[i] = record.Value
		}
		return result
	}
	return make([]string, 0)
}

// ChangeResourceRecordSet send a change resource record request to the AWS Route53 API
func (r *Route53) ChangeResourceRecordSet(req *ChangeResourceRecordSetsRequest, zoneId string) (*ChangeResourceRecordSetsResponse, error) {
	xmlBytes, err := xml.Marshal(req)
	if err != nil {
		return nil, err
	}
	xmlBytes = []byte(xml.Header + string(xmlBytes))

	result := new(ChangeResourceRecordSetsResponse)
	path := fmt.Sprintf("%s/%s/rrset", r.Endpoint, zoneId)
	err = r.query("POST", path, bytes.NewBuffer(xmlBytes), result)

	return result, err
}

// ListedHostedZones fetches a collection of HostedZones through the AWS Route53 API
func (r *Route53) ListHostedZones(marker string, maxItems int) (result *ListHostedZonesResponse, err error) {
	path := ""

	if marker == "" {
		path = fmt.Sprintf("%s?maxitems=%d", r.Endpoint, maxItems)
	} else {
		path = fmt.Sprintf("%s?marker=%v&maxitems=%d", r.Endpoint, marker, maxItems)
	}

	result = new(ListHostedZonesResponse)
	err = r.query("GET", path, nil, result)

	return
}

// GetHostedZone fetches a particular hostedzones DelegationSet by id
func (r *Route53) GetHostedZone(id string) (result *GetHostedZoneResponse, err error) {
	result = new(GetHostedZoneResponse)
	err = r.query("GET", fmt.Sprintf("%s/%v", r.Endpoint, id), nil, result)

	return
}

// DeleteHostedZone deletes the hosted zone with the given id
func (r *Route53) DeleteHostedZone(id string) (result *DeleteHostedZoneResponse, err error) {
	path := fmt.Sprintf("%s/%s", r.Endpoint, id)

	result = new(DeleteHostedZoneResponse)
	err = r.query("DELETE", path, nil, result)

	return
}

// AssociateVPCWithHostedZone associates a VPC with specified private hosted zone
func (r *Route53) AssociateVPCWithHostedZone(zoneid string, req *AssociateVPCWithHostedZoneRequest) (result *AssociateVPCWithHostedZoneResponse, err error) {
	xmlBytes, err := xml.Marshal(req)
	if err != nil {
		return nil, err
	}

	xmlBytes = []byte(xml.Header + string(xmlBytes))
	path := fmt.Sprintf("%s/%s/associatevpc", r.Endpoint, zoneid)
	result = new(AssociateVPCWithHostedZoneResponse)
	err = r.query("POST", path, bytes.NewBuffer(xmlBytes), result)

	return
}

// DisassociateVPCWithHostedZone disassociates a VPC from specified private hosted zone
func (r *Route53) DisassociateVPCWithHostedZone(zoneid string, req *DisassociateVPCWithHostedZoneRequest) (result *DisassociateVPCWithHostedZoneResponse, err error) {
	xmlBytes, err := xml.Marshal(req)
	if err != nil {
		return nil, err
	}

	xmlBytes = []byte(xml.Header + string(xmlBytes))
	path := fmt.Sprintf("%s/%s/disassociatevpc", r.Endpoint, zoneid)
	result = new(DisassociateVPCWithHostedZoneResponse)
	err = r.query("POST", path, bytes.NewBuffer(xmlBytes), result)

	return
}

func addParam(buffer *bytes.Buffer, name, value string) {
	if value != "" {
		if buffer.Len() > 0 {
			buffer.WriteString("&")
		}
		buffer.WriteString(fmt.Sprintf("%s=%s", name, value))
	}
}