~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/gopkg.in/amz.v3/ec2/ec2.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// goamz - Go packages to interact with the Amazon Web Services.
 
3
//
 
4
//   https://wiki.ubuntu.com/goamz
 
5
//
 
6
// Copyright (c) 2011 Canonical Ltd.
 
7
//
 
8
 
 
9
package ec2
 
10
 
 
11
import (
 
12
        "crypto/rand"
 
13
        "encoding/base64"
 
14
        "encoding/hex"
 
15
        "encoding/xml"
 
16
        "fmt"
 
17
        "log"
 
18
        "net/http"
 
19
        "net/http/httputil"
 
20
        "net/url"
 
21
        "sort"
 
22
        "strconv"
 
23
        "strings"
 
24
        "time"
 
25
 
 
26
        "gopkg.in/amz.v3/aws"
 
27
)
 
28
 
 
29
const (
 
30
        // debug, when set to true causes AWS requests and responses to be
 
31
        // printed in full.
 
32
        debug = false
 
33
 
 
34
        // apiVersion is the AWS API version used for all EC2 requests.
 
35
        apiVersion = "2014-10-01"
 
36
)
 
37
 
 
38
// The EC2 type encapsulates operations with a specific EC2 region.
 
39
type EC2 struct {
 
40
        aws.Auth
 
41
        aws.Region
 
42
        Sign    aws.Signer
 
43
        private byte // Reserve the right of using private data.
 
44
}
 
45
 
 
46
// New creates a new EC2.
 
47
func New(auth aws.Auth, region aws.Region, signer aws.Signer) *EC2 {
 
48
        return &EC2{auth, region, signer, 0}
 
49
}
 
50
 
 
51
// ----------------------------------------------------------------------------
 
52
// Filtering helper.
 
53
 
 
54
// Filter builds filtering parameters to be used in an EC2 query which supports
 
55
// filtering.  For example:
 
56
//
 
57
//     filter := NewFilter()
 
58
//     filter.Add("architecture", "i386")
 
59
//     filter.Add("launch-index", "0")
 
60
//     resp, err := ec2.Instances(nil, filter)
 
61
//
 
62
type Filter struct {
 
63
        m map[string][]string
 
64
}
 
65
 
 
66
// NewFilter creates a new Filter.
 
67
func NewFilter() *Filter {
 
68
        return &Filter{make(map[string][]string)}
 
69
}
 
70
 
 
71
// Add appends a filtering parameter with the given name and value(s).
 
72
func (f *Filter) Add(name string, value ...string) {
 
73
        f.m[name] = append(f.m[name], value...)
 
74
}
 
75
 
 
76
func (f *Filter) addParams(params map[string]string) {
 
77
        if f != nil {
 
78
                a := make([]string, len(f.m))
 
79
                i := 0
 
80
                for k := range f.m {
 
81
                        a[i] = k
 
82
                        i++
 
83
                }
 
84
                sort.StringSlice(a).Sort()
 
85
                for i, k := range a {
 
86
                        prefix := "Filter." + strconv.Itoa(i+1)
 
87
                        params[prefix+".Name"] = k
 
88
                        for j, v := range f.m[k] {
 
89
                                params[prefix+".Value."+strconv.Itoa(j+1)] = v
 
90
                        }
 
91
                }
 
92
        }
 
93
}
 
94
 
 
95
// ----------------------------------------------------------------------------
 
96
// Request dispatching logic.
 
97
 
 
98
// Error encapsulates an error returned by EC2.
 
99
//
 
100
// See http://goo.gl/VZGuC for more details.
 
101
type Error struct {
 
102
        // HTTP status code (200, 403, ...)
 
103
        StatusCode int
 
104
        // EC2 error code ("UnsupportedOperation", ...)
 
105
        Code string
 
106
        // The human-oriented error message
 
107
        Message   string
 
108
        RequestId string `xml:"RequestID"`
 
109
}
 
110
 
 
111
func (err *Error) Error() string {
 
112
        if err.Code == "" {
 
113
                return err.Message
 
114
        }
 
115
 
 
116
        return fmt.Sprintf("%s (%s)", err.Message, err.Code)
 
117
}
 
118
 
 
119
// For now a single error inst is being exposed. In the future it may be useful
 
120
// to provide access to all of them, but rather than doing it as an array/slice,
 
121
// use a *next pointer, so that it's backward compatible and it continues to be
 
122
// easy to handle the first error, which is what most people will want.
 
123
type xmlErrors struct {
 
124
        RequestId string  `xml:"RequestID"`
 
125
        Errors    []Error `xml:"Errors>Error"`
 
126
}
 
127
 
 
128
var timeNow = time.Now
 
129
 
 
130
// resp = response structure that will get inflated by XML unmarshaling.
 
131
func (ec2 *EC2) query(params map[string]string, resp interface{}) error {
 
132
 
 
133
        req, err := http.NewRequest("GET", ec2.Region.EC2Endpoint, nil)
 
134
        if err != nil {
 
135
                return err
 
136
        }
 
137
 
 
138
        // Add the params passed in to the query string
 
139
        query := req.URL.Query()
 
140
        for varName, varVal := range params {
 
141
                query.Add(varName, varVal)
 
142
        }
 
143
        query.Add("Timestamp", timeNow().In(time.UTC).Format(time.RFC3339))
 
144
        req.URL.RawQuery = query.Encode()
 
145
        req.Header.Set("x-amz-date", time.Now().In(time.UTC).Format(aws.ISO8601BasicFormat))
 
146
 
 
147
        if err := ec2.Sign(req, ec2.Auth); err != nil {
 
148
                return err
 
149
        }
 
150
 
 
151
        r, err := http.DefaultClient.Do(req)
 
152
        if err != nil {
 
153
                return err
 
154
        }
 
155
        defer r.Body.Close()
 
156
 
 
157
        if debug {
 
158
                dumpRequest(req)
 
159
                dump, _ := httputil.DumpResponse(r, true)
 
160
                log.Printf("response:\n%v\n}\n", string(dump))
 
161
        }
 
162
        if r.StatusCode != 200 {
 
163
                return buildError(r)
 
164
        }
 
165
        return xml.NewDecoder(r.Body).Decode(resp)
 
166
}
 
167
 
 
168
// dumpRequest pretty-prints the AWS request the way the API docs
 
169
// formats it.
 
170
func dumpRequest(req *http.Request) {
 
171
        queryParts := strings.Split(req.URL.RawQuery, "&")
 
172
        path := req.URL.Path
 
173
        if path == "" {
 
174
                path = "/"
 
175
        }
 
176
        reqURL := path + "?" + queryParts[0] + "\n\t&" + strings.Join(queryParts[1:], "\n\t&")
 
177
        log.Printf("request: %s %s %s\n}\n", req.Method, reqURL, req.Proto)
 
178
}
 
179
 
 
180
func multimap(p map[string]string) url.Values {
 
181
        q := make(url.Values, len(p))
 
182
        for k, v := range p {
 
183
                q[k] = []string{v}
 
184
        }
 
185
        return q
 
186
}
 
187
 
 
188
func buildError(r *http.Response) error {
 
189
        errors := xmlErrors{}
 
190
        xml.NewDecoder(r.Body).Decode(&errors)
 
191
        var err Error
 
192
        if len(errors.Errors) > 0 {
 
193
                err = errors.Errors[0]
 
194
        }
 
195
        err.RequestId = errors.RequestId
 
196
        err.StatusCode = r.StatusCode
 
197
        if err.Message == "" {
 
198
                err.Message = r.Status
 
199
        }
 
200
        return &err
 
201
}
 
202
 
 
203
func makeParams(action string) map[string]string {
 
204
        params := make(map[string]string)
 
205
        params["Action"] = action
 
206
        params["Version"] = apiVersion
 
207
        return params
 
208
}
 
209
 
 
210
func addParamsList(params map[string]string, label string, ids []string) {
 
211
        for i, id := range ids {
 
212
                params[label+"."+strconv.Itoa(i+1)] = id
 
213
        }
 
214
}
 
215
 
 
216
// ----------------------------------------------------------------------------
 
217
// Instance management functions and types.
 
218
 
 
219
// RunNetworkInterface encapsulates options for a single network
 
220
// interface, specified when calling RunInstances.
 
221
//
 
222
// If Id is set, it must match an existing VPC network interface, and
 
223
// in this case only a single instance can be launched. If Id is not
 
224
// set, a new network interface will be created for each instance.
 
225
//
 
226
// The following fields are required when creating a new network
 
227
// interface (i.e. Id is empty): DeviceIndex, SubnetId, Description
 
228
// (only used if set), SecurityGroupIds.
 
229
//
 
230
// PrivateIPs can be used to add one or more private IP addresses to a
 
231
// network interface. Only one of the IP addresses can be set as
 
232
// primary. If none are given, EC2 selects a primary IP for each
 
233
// created interface from the subnet pool.
 
234
//
 
235
// When SecondaryPrivateIPCount is non-zero, EC2 allocates that number
 
236
// of IP addresses from within the subnet range and sets them as
 
237
// secondary IPs. The number of IP addresses that can be assigned to a
 
238
// network interface varies by instance type.
 
239
type RunNetworkInterface struct {
 
240
        Id                      string
 
241
        DeviceIndex             int
 
242
        SubnetId                string
 
243
        Description             string
 
244
        PrivateIPs              []PrivateIP
 
245
        SecurityGroupIds        []string
 
246
        DeleteOnTermination     bool
 
247
        SecondaryPrivateIPCount int
 
248
}
 
249
 
 
250
// The RunInstances type encapsulates options for the respective request in EC2.
 
251
//
 
252
// See http://goo.gl/Mcm3b for more details.
 
253
type RunInstances struct {
 
254
        ImageId               string
 
255
        MinCount              int
 
256
        MaxCount              int
 
257
        KeyName               string
 
258
        InstanceType          string
 
259
        SecurityGroups        []SecurityGroup
 
260
        KernelId              string
 
261
        RamdiskId             string
 
262
        UserData              []byte
 
263
        AvailZone             string
 
264
        PlacementGroupName    string
 
265
        Monitoring            bool
 
266
        SubnetId              string
 
267
        DisableAPITermination bool
 
268
        ShutdownBehavior      string
 
269
        PrivateIPAddress      string
 
270
        IAMInstanceProfile    string
 
271
        BlockDeviceMappings   []BlockDeviceMapping
 
272
        NetworkInterfaces     []RunNetworkInterface
 
273
        EBSOptimized          bool
 
274
}
 
275
 
 
276
// Response to a RunInstances request.
 
277
//
 
278
// See http://goo.gl/Mcm3b for more details.
 
279
type RunInstancesResp struct {
 
280
        RequestId      string          `xml:"requestId"`
 
281
        ReservationId  string          `xml:"reservationId"`
 
282
        OwnerId        string          `xml:"ownerId"`
 
283
        SecurityGroups []SecurityGroup `xml:"groupSet>item"`
 
284
        Instances      []Instance      `xml:"instancesSet>item"`
 
285
}
 
286
 
 
287
// Instance encapsulates a running instance in EC2.
 
288
//
 
289
// See http://goo.gl/OCH8a for more details.
 
290
type Instance struct {
 
291
        InstanceId          string                       `xml:"instanceId"`
 
292
        InstanceType        string                       `xml:"instanceType"`
 
293
        ImageId             string                       `xml:"imageId"`
 
294
        IAMInstanceProfile  string                       `xml:"iamInstanceProfile>id"`
 
295
        PrivateDNSName      string                       `xml:"privateDnsName"`
 
296
        DNSName             string                       `xml:"dnsName"`
 
297
        IPAddress           string                       `xml:"ipAddress"`
 
298
        PrivateIPAddress    string                       `xml:"privateIpAddress"`
 
299
        SubnetId            string                       `xml:"subnetId"`
 
300
        VPCId               string                       `xml:"vpcId"`
 
301
        SourceDestCheck     bool                         `xml:"sourceDestCheck"`
 
302
        KeyName             string                       `xml:"keyName"`
 
303
        AMILaunchIndex      int                          `xml:"amiLaunchIndex"`
 
304
        Hypervisor          string                       `xml:"hypervisor"`
 
305
        VirtType            string                       `xml:"virtualizationType"`
 
306
        Monitoring          string                       `xml:"monitoring>state"`
 
307
        AvailZone           string                       `xml:"placement>availabilityZone"`
 
308
        AssociatePublicIP   bool                         `xml:"associatePublicIpAddress,omitempty"`
 
309
        PlacementGroupName  string                       `xml:"placement>groupName"`
 
310
        EBSOptimized        bool                         `xml:"ebsOptimized,omitempty"`
 
311
        SRIOVNetSupport     bool                         `xml:"sriovNetSupport,omitempty"`
 
312
        State               InstanceState                `xml:"instanceState"`
 
313
        Tags                []Tag                        `xml:"tagSet>item"`
 
314
        SecurityGroups      []SecurityGroup              `xml:"groupSet>item"`
 
315
        NetworkInterfaces   []NetworkInterface           `xml:"networkInterfaceSet>item"`
 
316
        BlockDeviceMappings []InstanceBlockDeviceMapping `xml:"blockDeviceMapping>item"`
 
317
        RootDeviceType      string                       `xml:"rootDeviceType"`
 
318
        RootDeviceName      string                       `xml:"rootDeviceName"`
 
319
}
 
320
 
 
321
// InstanceBlockDeviceMapping describes a block device mapping.
 
322
//
 
323
// See http://goo.gl/Ua0BIw for more details.
 
324
type InstanceBlockDeviceMapping struct {
 
325
        DeviceName          string `xml:"deviceName"`
 
326
        AttachTime          string `xml:"ebs>attachTime"`
 
327
        DeleteOnTermination bool   `xml:"ebs>deleteOnTermination"`
 
328
        Status              string `xml:"ebs>status"`
 
329
        VolumeId            string `xml:"ebs>volumeId"`
 
330
}
 
331
 
 
332
// RunInstances starts new instances in EC2.
 
333
// If options.MinCount and options.MaxCount are both zero, a single instance
 
334
// will be started; otherwise if options.MaxCount is zero, options.MinCount
 
335
// will be used instead.
 
336
//
 
337
// See http://goo.gl/Mcm3b for more details.
 
338
func (ec2 *EC2) RunInstances(options *RunInstances) (resp *RunInstancesResp, err error) {
 
339
        params := makeParams("RunInstances")
 
340
        params["ImageId"] = options.ImageId
 
341
        params["InstanceType"] = options.InstanceType
 
342
        var min, max int
 
343
        if options.MinCount == 0 && options.MaxCount == 0 {
 
344
                min = 1
 
345
                max = 1
 
346
        } else if options.MaxCount == 0 {
 
347
                min = options.MinCount
 
348
                max = min
 
349
        } else {
 
350
                min = options.MinCount
 
351
                max = options.MaxCount
 
352
        }
 
353
        params["MinCount"] = strconv.Itoa(min)
 
354
        params["MaxCount"] = strconv.Itoa(max)
 
355
        i, j := 1, 1
 
356
        for _, g := range options.SecurityGroups {
 
357
                if g.Id != "" {
 
358
                        params["SecurityGroupId."+strconv.Itoa(i)] = g.Id
 
359
                        i++
 
360
                } else {
 
361
                        params["SecurityGroup."+strconv.Itoa(j)] = g.Name
 
362
                        j++
 
363
                }
 
364
        }
 
365
        prepareBlockDevices(params, options.BlockDeviceMappings)
 
366
        prepareNetworkInterfaces(params, options.NetworkInterfaces)
 
367
        token, err := clientToken()
 
368
        if err != nil {
 
369
                return nil, err
 
370
        }
 
371
        params["ClientToken"] = token
 
372
 
 
373
        if options.KeyName != "" {
 
374
                params["KeyName"] = options.KeyName
 
375
        }
 
376
        if options.KernelId != "" {
 
377
                params["KernelId"] = options.KernelId
 
378
        }
 
379
        if options.RamdiskId != "" {
 
380
                params["RamdiskId"] = options.RamdiskId
 
381
        }
 
382
        if options.UserData != nil {
 
383
                userData := make([]byte, base64.StdEncoding.EncodedLen(len(options.UserData)))
 
384
                base64.StdEncoding.Encode(userData, options.UserData)
 
385
                params["UserData"] = string(userData)
 
386
        }
 
387
        if options.AvailZone != "" {
 
388
                params["Placement.AvailabilityZone"] = options.AvailZone
 
389
        }
 
390
        if options.PlacementGroupName != "" {
 
391
                params["Placement.GroupName"] = options.PlacementGroupName
 
392
        }
 
393
        if options.Monitoring {
 
394
                params["Monitoring.Enabled"] = "true"
 
395
        }
 
396
        if options.SubnetId != "" {
 
397
                params["SubnetId"] = options.SubnetId
 
398
        }
 
399
        if options.DisableAPITermination {
 
400
                params["DisableApiTermination"] = "true"
 
401
        }
 
402
        if options.ShutdownBehavior != "" {
 
403
                params["InstanceInitiatedShutdownBehavior"] = options.ShutdownBehavior
 
404
        }
 
405
        if options.PrivateIPAddress != "" {
 
406
                params["PrivateIpAddress"] = options.PrivateIPAddress
 
407
        }
 
408
        if options.IAMInstanceProfile != "" {
 
409
                params["IamInstanceProfile.Name"] = options.IAMInstanceProfile
 
410
        }
 
411
        if options.EBSOptimized {
 
412
                params["EbsOptimized"] = "true"
 
413
        }
 
414
 
 
415
        resp = &RunInstancesResp{}
 
416
        err = ec2.query(params, resp)
 
417
        if err != nil {
 
418
                return nil, err
 
419
        }
 
420
        return
 
421
}
 
422
 
 
423
func prepareBlockDevices(params map[string]string, blockDevs []BlockDeviceMapping) {
 
424
        for i, b := range blockDevs {
 
425
                n := strconv.Itoa(i + 1)
 
426
                prefix := "BlockDeviceMapping." + n
 
427
                if b.DeviceName != "" {
 
428
                        params[prefix+".DeviceName"] = b.DeviceName
 
429
                }
 
430
                if b.VirtualName != "" {
 
431
                        params[prefix+".VirtualName"] = b.VirtualName
 
432
                }
 
433
                if b.SnapshotId != "" {
 
434
                        params[prefix+".Ebs.SnapshotId"] = b.SnapshotId
 
435
                }
 
436
                if b.VolumeType != "" {
 
437
                        params[prefix+".Ebs.VolumeType"] = b.VolumeType
 
438
                }
 
439
                if b.VolumeSize > 0 {
 
440
                        params[prefix+".Ebs.VolumeSize"] = strconv.FormatInt(b.VolumeSize, 10)
 
441
                }
 
442
                if b.IOPS > 0 {
 
443
                        params[prefix+".Ebs.Iops"] = strconv.FormatInt(b.IOPS, 10)
 
444
                }
 
445
                if b.DeleteOnTermination {
 
446
                        params[prefix+".Ebs.DeleteOnTermination"] = "true"
 
447
                }
 
448
        }
 
449
}
 
450
 
 
451
func prepareNetworkInterfaces(params map[string]string, nics []RunNetworkInterface) {
 
452
        for i, ni := range nics {
 
453
                // Unlike other lists, NetworkInterface and PrivateIpAddresses
 
454
                // should start from 0, not 1, according to the examples
 
455
                // requests in the API documentation here http://goo.gl/Mcm3b.
 
456
                n := strconv.Itoa(i)
 
457
                prefix := "NetworkInterface." + n
 
458
                if ni.Id != "" {
 
459
                        params[prefix+".NetworkInterfaceId"] = ni.Id
 
460
                }
 
461
                params[prefix+".DeviceIndex"] = strconv.Itoa(ni.DeviceIndex)
 
462
                if ni.SubnetId != "" {
 
463
                        params[prefix+".SubnetId"] = ni.SubnetId
 
464
                }
 
465
                if ni.Description != "" {
 
466
                        params[prefix+".Description"] = ni.Description
 
467
                }
 
468
                for j, gid := range ni.SecurityGroupIds {
 
469
                        k := strconv.Itoa(j + 1)
 
470
                        params[prefix+".SecurityGroupId."+k] = gid
 
471
                }
 
472
                if ni.DeleteOnTermination {
 
473
                        params[prefix+".DeleteOnTermination"] = "true"
 
474
                }
 
475
                if ni.SecondaryPrivateIPCount > 0 {
 
476
                        val := strconv.Itoa(ni.SecondaryPrivateIPCount)
 
477
                        params[prefix+".SecondaryPrivateIpAddressCount"] = val
 
478
                }
 
479
                for j, ip := range ni.PrivateIPs {
 
480
                        k := strconv.Itoa(j)
 
481
                        subprefix := prefix + ".PrivateIpAddresses." + k
 
482
                        params[subprefix+".PrivateIpAddress"] = ip.Address
 
483
                        params[subprefix+".Primary"] = strconv.FormatBool(ip.IsPrimary)
 
484
                }
 
485
        }
 
486
}
 
487
 
 
488
func clientToken() (string, error) {
 
489
        // Maximum EC2 client token size is 64 bytes.
 
490
        // Each byte expands to two when hex encoded.
 
491
        buf := make([]byte, 32)
 
492
        _, err := rand.Read(buf)
 
493
        if err != nil {
 
494
                return "", err
 
495
        }
 
496
        return hex.EncodeToString(buf), nil
 
497
}
 
498
 
 
499
// Response to a TerminateInstances request.
 
500
//
 
501
// See http://goo.gl/3BKHj for more details.
 
502
type TerminateInstancesResp struct {
 
503
        RequestId    string                `xml:"requestId"`
 
504
        StateChanges []InstanceStateChange `xml:"instancesSet>item"`
 
505
}
 
506
 
 
507
// InstanceState encapsulates the state of an instance in EC2.
 
508
//
 
509
// See http://goo.gl/y3ZBq for more details.
 
510
type InstanceState struct {
 
511
        Code int    `xml:"code"` // Watch out, bits 15-8 have unpublished meaning.
 
512
        Name string `xml:"name"`
 
513
}
 
514
 
 
515
// InstanceStateChange informs of the previous and current states
 
516
// for an instance when a state change is requested.
 
517
type InstanceStateChange struct {
 
518
        InstanceId    string        `xml:"instanceId"`
 
519
        CurrentState  InstanceState `xml:"currentState"`
 
520
        PreviousState InstanceState `xml:"previousState"`
 
521
}
 
522
 
 
523
// TerminateInstances requests the termination of instances when the given ids.
 
524
//
 
525
// See http://goo.gl/3BKHj for more details.
 
526
func (ec2 *EC2) TerminateInstances(instIds []string) (resp *TerminateInstancesResp, err error) {
 
527
        params := makeParams("TerminateInstances")
 
528
        addParamsList(params, "InstanceId", instIds)
 
529
        resp = &TerminateInstancesResp{}
 
530
        err = ec2.query(params, resp)
 
531
        if err != nil {
 
532
                return nil, err
 
533
        }
 
534
        return
 
535
}
 
536
 
 
537
// Response to a DescribeInstances request.
 
538
//
 
539
// See http://goo.gl/mLbmw for more details.
 
540
type InstancesResp struct {
 
541
        RequestId    string        `xml:"requestId"`
 
542
        Reservations []Reservation `xml:"reservationSet>item"`
 
543
}
 
544
 
 
545
// Reservation represents details about a reservation in EC2.
 
546
//
 
547
// See http://goo.gl/0ItPT for more details.
 
548
type Reservation struct {
 
549
        ReservationId  string          `xml:"reservationId"`
 
550
        OwnerId        string          `xml:"ownerId"`
 
551
        RequesterId    string          `xml:"requesterId"`
 
552
        SecurityGroups []SecurityGroup `xml:"groupSet>item"`
 
553
        Instances      []Instance      `xml:"instancesSet>item"`
 
554
}
 
555
 
 
556
// Instances returns details about instances in EC2.  Both parameters
 
557
// are optional, and if provided will limit the instances returned to those
 
558
// matching the given instance ids or filtering rules.
 
559
//
 
560
// See http://goo.gl/4No7c for more details.
 
561
func (ec2 *EC2) Instances(instIds []string, filter *Filter) (resp *InstancesResp, err error) {
 
562
        params := makeParams("DescribeInstances")
 
563
        addParamsList(params, "InstanceId", instIds)
 
564
        filter.addParams(params)
 
565
        resp = &InstancesResp{}
 
566
        err = ec2.query(params, resp)
 
567
        if err != nil {
 
568
                return nil, err
 
569
        }
 
570
        return
 
571
}
 
572
 
 
573
// The ModifyInstanceAttribute type encapsulates options for the respective
 
574
// request in EC2.
 
575
//
 
576
// See http://goo.gl/cTxLa7 for more details.
 
577
type ModifyInstanceAttribute struct {
 
578
        InstanceId          string
 
579
        SourceDestCheck     *bool
 
580
        BlockDeviceMappings []InstanceBlockDeviceMapping
 
581
}
 
582
 
 
583
// ModifyInstanceAttribute modifies a single attribute of an instance in EC2.
 
584
//
 
585
// See http://goo.gl/cTxLa7 for more details.
 
586
func (ec2 *EC2) ModifyInstanceAttribute(req *ModifyInstanceAttribute, filter *Filter) (resp *SimpleResp, err error) {
 
587
        params := makeParams("ModifyInstanceAttribute")
 
588
        params["InstanceId"] = req.InstanceId
 
589
        if req.SourceDestCheck != nil {
 
590
                params["SourceDestCheck.Value"] = fmt.Sprint(*req.SourceDestCheck)
 
591
        }
 
592
        if req.BlockDeviceMappings != nil {
 
593
                for i, b := range req.BlockDeviceMappings {
 
594
                        n := strconv.Itoa(i + 1)
 
595
                        prefix := "BlockDeviceMapping." + n
 
596
                        if b.DeviceName != "" {
 
597
                                params[prefix+".DeviceName"] = b.DeviceName
 
598
                        }
 
599
                        if b.VolumeId != "" {
 
600
                                params[prefix+".Ebs.VolumeId"] = b.VolumeId
 
601
                        }
 
602
                        params[prefix+".Ebs.DeleteOnTermination"] = fmt.Sprint(b.DeleteOnTermination)
 
603
                }
 
604
        }
 
605
        filter.addParams(params)
 
606
        resp = &SimpleResp{}
 
607
        err = ec2.query(params, resp)
 
608
        if err != nil {
 
609
                return nil, err
 
610
        }
 
611
        return
 
612
}
 
613
 
 
614
// ----------------------------------------------------------------------------
 
615
// Image and snapshot management functions and types.
 
616
 
 
617
// Response to a DescribeImages request.
 
618
//
 
619
// See http://goo.gl/hLnyg for more details.
 
620
type ImagesResp struct {
 
621
        RequestId string  `xml:"requestId"`
 
622
        Images    []Image `xml:"imagesSet>item"`
 
623
}
 
624
 
 
625
// BlockDeviceMapping represents the association of a block device with an image.
 
626
//
 
627
// See http://goo.gl/wnDBf for more details.
 
628
type BlockDeviceMapping struct {
 
629
        DeviceName          string `xml:"deviceName"`
 
630
        VirtualName         string `xml:"virtualName"`
 
631
        SnapshotId          string `xml:"ebs>snapshotId"`
 
632
        VolumeType          string `xml:"ebs>volumeType"`
 
633
        VolumeSize          int64  `xml:"ebs>volumeSize"` // Size is given in GB
 
634
        DeleteOnTermination bool   `xml:"ebs>deleteOnTermination"`
 
635
 
 
636
        // The number of I/O operations per second (IOPS) that the volume supports.
 
637
        IOPS int64 `xml:"ebs>iops"`
 
638
}
 
639
 
 
640
// Image represents details about an image.
 
641
//
 
642
// See http://goo.gl/iSqJG for more details.
 
643
type Image struct {
 
644
        Id                 string               `xml:"imageId"`
 
645
        Name               string               `xml:"name"`
 
646
        Description        string               `xml:"description"`
 
647
        Type               string               `xml:"imageType"`
 
648
        State              string               `xml:"imageState"`
 
649
        Location           string               `xml:"imageLocation"`
 
650
        Public             bool                 `xml:"isPublic"`
 
651
        Architecture       string               `xml:"architecture"`
 
652
        Platform           string               `xml:"platform"`
 
653
        ProductCodes       []string             `xml:"productCode>item>productCode"`
 
654
        KernelId           string               `xml:"kernelId"`
 
655
        RamdiskId          string               `xml:"ramdiskId"`
 
656
        StateReason        string               `xml:"stateReason"`
 
657
        OwnerId            string               `xml:"imageOwnerId"`
 
658
        OwnerAlias         string               `xml:"imageOwnerAlias"`
 
659
        RootDeviceType     string               `xml:"rootDeviceType"`
 
660
        RootDeviceName     string               `xml:"rootDeviceName"`
 
661
        VirtualizationType string               `xml:"virtualizationType"`
 
662
        Hypervisor         string               `xml:"hypervisor"`
 
663
        SRIOVNetSupport    bool                 `xml:"sriovNetSupport,omitempty"`
 
664
        BlockDevices       []BlockDeviceMapping `xml:"blockDeviceMapping>item"`
 
665
}
 
666
 
 
667
// Images returns details about available images.
 
668
// The ids and filter parameters, if provided, will limit the images returned.
 
669
// For example, to get all the private images associated with this account set
 
670
// the boolean filter "is-private" to true.
 
671
//
 
672
// Note: calling this function with nil ids and filter parameters will result in
 
673
// a very large number of images being returned.
 
674
//
 
675
// See http://goo.gl/SRBhW for more details.
 
676
func (ec2 *EC2) Images(ids []string, filter *Filter) (resp *ImagesResp, err error) {
 
677
        params := makeParams("DescribeImages")
 
678
        for i, id := range ids {
 
679
                params["ImageId."+strconv.Itoa(i+1)] = id
 
680
        }
 
681
        filter.addParams(params)
 
682
 
 
683
        resp = &ImagesResp{}
 
684
        err = ec2.query(params, resp)
 
685
        if err != nil {
 
686
                return nil, err
 
687
        }
 
688
        return
 
689
}
 
690
 
 
691
// Response to a CreateSnapshot request.
 
692
//
 
693
// See http://goo.gl/ttcda for more details.
 
694
type CreateSnapshotResp struct {
 
695
        RequestId string `xml:"requestId"`
 
696
        Snapshot
 
697
}
 
698
 
 
699
// CreateSnapshot creates a volume snapshot and stores it in S3.
 
700
//
 
701
// See http://goo.gl/ttcda for more details.
 
702
func (ec2 *EC2) CreateSnapshot(volumeId, description string) (resp *CreateSnapshotResp, err error) {
 
703
        params := makeParams("CreateSnapshot")
 
704
        params["VolumeId"] = volumeId
 
705
        params["Description"] = description
 
706
 
 
707
        resp = &CreateSnapshotResp{}
 
708
        err = ec2.query(params, resp)
 
709
        if err != nil {
 
710
                return nil, err
 
711
        }
 
712
        return
 
713
}
 
714
 
 
715
// DeleteSnapshots deletes the volume snapshots with the given ids.
 
716
//
 
717
// Note: If you make periodic snapshots of a volume, the snapshots are
 
718
// incremental so that only the blocks on the device that have changed
 
719
// since your last snapshot are incrementally saved in the new snapshot.
 
720
// Even though snapshots are saved incrementally, the snapshot deletion
 
721
// process is designed so that you need to retain only the most recent
 
722
// snapshot in order to restore the volume.
 
723
//
 
724
// See http://goo.gl/vwU1y for more details.
 
725
func (ec2 *EC2) DeleteSnapshots(ids []string) (resp *SimpleResp, err error) {
 
726
        params := makeParams("DeleteSnapshot")
 
727
        for i, id := range ids {
 
728
                params["SnapshotId."+strconv.Itoa(i+1)] = id
 
729
        }
 
730
 
 
731
        resp = &SimpleResp{}
 
732
        err = ec2.query(params, resp)
 
733
        if err != nil {
 
734
                return nil, err
 
735
        }
 
736
        return
 
737
}
 
738
 
 
739
// Response to a DescribeSnapshots request.
 
740
//
 
741
// See http://goo.gl/nClDT for more details.
 
742
type SnapshotsResp struct {
 
743
        RequestId string     `xml:"requestId"`
 
744
        Snapshots []Snapshot `xml:"snapshotSet>item"`
 
745
}
 
746
 
 
747
// Snapshot represents details about a volume snapshot.
 
748
//
 
749
// See http://goo.gl/nkovs for more details.
 
750
type Snapshot struct {
 
751
        Id          string `xml:"snapshotId"`
 
752
        VolumeId    string `xml:"volumeId"`
 
753
        VolumeSize  string `xml:"volumeSize"`
 
754
        Status      string `xml:"status"`
 
755
        StartTime   string `xml:"startTime"`
 
756
        Description string `xml:"description"`
 
757
        Progress    string `xml:"progress"`
 
758
        OwnerId     string `xml:"ownerId"`
 
759
        OwnerAlias  string `xml:"ownerAlias"`
 
760
        Tags        []Tag  `xml:"tagSet>item"`
 
761
}
 
762
 
 
763
// Snapshots returns details about volume snapshots available to the user.
 
764
// The ids and filter parameters, if provided, limit the snapshots returned.
 
765
//
 
766
// See http://goo.gl/ogJL4 for more details.
 
767
func (ec2 *EC2) Snapshots(ids []string, filter *Filter) (resp *SnapshotsResp, err error) {
 
768
        params := makeParams("DescribeSnapshots")
 
769
        for i, id := range ids {
 
770
                params["SnapshotId."+strconv.Itoa(i+1)] = id
 
771
        }
 
772
        filter.addParams(params)
 
773
 
 
774
        resp = &SnapshotsResp{}
 
775
        err = ec2.query(params, resp)
 
776
        if err != nil {
 
777
                return nil, err
 
778
        }
 
779
        return
 
780
}
 
781
 
 
782
// ----------------------------------------------------------------------------
 
783
// Security group management functions and types.
 
784
 
 
785
// SimpleResp represents a response to an EC2 request which on success will
 
786
// return no other information besides a request id.
 
787
type SimpleResp struct {
 
788
        XMLName   xml.Name
 
789
        RequestId string `xml:"requestId"`
 
790
        Return    bool   `xml:"return"`
 
791
}
 
792
 
 
793
// CreateSecurityGroupResp represents a response to a CreateSecurityGroup request.
 
794
type CreateSecurityGroupResp struct {
 
795
        SecurityGroup
 
796
        RequestId string `xml:"requestId"`
 
797
}
 
798
 
 
799
// CreateSecurityGroup creates a security group with the provided name
 
800
// and description. The vpcId argument can be empty to create a
 
801
// EC2-Classic group, instead of EC2-VPC one.
 
802
//
 
803
// See http://goo.gl/Eo7Yl for more details.
 
804
func (ec2 *EC2) CreateSecurityGroup(vpcId, name, description string) (resp *CreateSecurityGroupResp, err error) {
 
805
        params := makeParams("CreateSecurityGroup")
 
806
        params["GroupName"] = name
 
807
        params["GroupDescription"] = description
 
808
        if vpcId != "" {
 
809
                params["VpcId"] = vpcId
 
810
        }
 
811
 
 
812
        resp = &CreateSecurityGroupResp{}
 
813
        err = ec2.query(params, resp)
 
814
        if err != nil {
 
815
                return nil, err
 
816
        }
 
817
        resp.Name = name
 
818
        return resp, nil
 
819
}
 
820
 
 
821
// SecurityGroupsResp represents a response to a DescribeSecurityGroups
 
822
// request in EC2.
 
823
//
 
824
// See http://goo.gl/k12Uy for more details.
 
825
type SecurityGroupsResp struct {
 
826
        RequestId string              `xml:"requestId"`
 
827
        Groups    []SecurityGroupInfo `xml:"securityGroupInfo>item"`
 
828
}
 
829
 
 
830
// SecurityGroup encapsulates details for a security group in EC2.
 
831
//
 
832
// See http://goo.gl/CIdyP for more details.
 
833
type SecurityGroupInfo struct {
 
834
        SecurityGroup
 
835
        VPCId       string   `xml:"vpcId"`
 
836
        OwnerId     string   `xml:"ownerId"`
 
837
        Description string   `xml:"groupDescription"`
 
838
        IPPerms     []IPPerm `xml:"ipPermissions>item"`
 
839
}
 
840
 
 
841
// IPPerm represents an allowance within an EC2 security group.
 
842
//
 
843
// See http://goo.gl/4oTxv for more details.
 
844
type IPPerm struct {
 
845
        Protocol     string              `xml:"ipProtocol"`
 
846
        FromPort     int                 `xml:"fromPort"`
 
847
        ToPort       int                 `xml:"toPort"`
 
848
        SourceIPs    []string            `xml:"ipRanges>item>cidrIp"`
 
849
        SourceGroups []UserSecurityGroup `xml:"groups>item"`
 
850
}
 
851
 
 
852
// UserSecurityGroup holds a security group and the owner
 
853
// of that group.
 
854
type UserSecurityGroup struct {
 
855
        Id      string `xml:"groupId"`
 
856
        Name    string `xml:"groupName,omitempty"`
 
857
        OwnerId string `xml:"userId"`
 
858
}
 
859
 
 
860
// SecurityGroup represents an EC2 security group.
 
861
// If SecurityGroup is used as a parameter, then one of Id or Name
 
862
// may be empty. If both are set, then Id is used.
 
863
type SecurityGroup struct {
 
864
        Id   string `xml:"groupId"`
 
865
        Name string `xml:"groupName"`
 
866
}
 
867
 
 
868
// SecurityGroupNames is a convenience function that
 
869
// returns a slice of security groups with the given names.
 
870
func SecurityGroupNames(names ...string) []SecurityGroup {
 
871
        g := make([]SecurityGroup, len(names))
 
872
        for i, name := range names {
 
873
                g[i] = SecurityGroup{Name: name}
 
874
        }
 
875
        return g
 
876
}
 
877
 
 
878
// SecurityGroupNames is a convenience function that
 
879
// returns a slice of security groups with the given ids.
 
880
func SecurityGroupIds(ids ...string) []SecurityGroup {
 
881
        g := make([]SecurityGroup, len(ids))
 
882
        for i, id := range ids {
 
883
                g[i] = SecurityGroup{Id: id}
 
884
        }
 
885
        return g
 
886
}
 
887
 
 
888
// SecurityGroups returns details about security groups in EC2.  Both parameters
 
889
// are optional, and if provided will limit the security groups returned to those
 
890
// matching the given groups or filtering rules.
 
891
//
 
892
// See http://goo.gl/k12Uy for more details.
 
893
func (ec2 *EC2) SecurityGroups(groups []SecurityGroup, filter *Filter) (resp *SecurityGroupsResp, err error) {
 
894
        params := makeParams("DescribeSecurityGroups")
 
895
        i, j := 1, 1
 
896
        for _, g := range groups {
 
897
                if g.Id != "" {
 
898
                        params["GroupId."+strconv.Itoa(i)] = g.Id
 
899
                        i++
 
900
                } else {
 
901
                        params["GroupName."+strconv.Itoa(j)] = g.Name
 
902
                        j++
 
903
                }
 
904
        }
 
905
        filter.addParams(params)
 
906
 
 
907
        resp = &SecurityGroupsResp{}
 
908
        err = ec2.query(params, resp)
 
909
        if err != nil {
 
910
                return nil, err
 
911
        }
 
912
        return resp, nil
 
913
}
 
914
 
 
915
// DeleteSecurityGroup removes the given security group in EC2.
 
916
//
 
917
// See http://goo.gl/QJJDO for more details.
 
918
func (ec2 *EC2) DeleteSecurityGroup(group SecurityGroup) (resp *SimpleResp, err error) {
 
919
        params := makeParams("DeleteSecurityGroup")
 
920
        if group.Id != "" {
 
921
                params["GroupId"] = group.Id
 
922
        } else {
 
923
                params["GroupName"] = group.Name
 
924
        }
 
925
 
 
926
        resp = &SimpleResp{}
 
927
        err = ec2.query(params, resp)
 
928
        if err != nil {
 
929
                return nil, err
 
930
        }
 
931
        return resp, nil
 
932
}
 
933
 
 
934
// AuthorizeSecurityGroup creates an allowance for clients matching the provided
 
935
// rules to access instances within the given security group.
 
936
//
 
937
// See http://goo.gl/u2sDJ for more details.
 
938
func (ec2 *EC2) AuthorizeSecurityGroup(group SecurityGroup, perms []IPPerm) (resp *SimpleResp, err error) {
 
939
        return ec2.authOrRevoke("AuthorizeSecurityGroupIngress", group, perms)
 
940
}
 
941
 
 
942
// RevokeSecurityGroup revokes permissions from a group.
 
943
//
 
944
// See http://goo.gl/ZgdxA for more details.
 
945
func (ec2 *EC2) RevokeSecurityGroup(group SecurityGroup, perms []IPPerm) (resp *SimpleResp, err error) {
 
946
        return ec2.authOrRevoke("RevokeSecurityGroupIngress", group, perms)
 
947
}
 
948
 
 
949
func (ec2 *EC2) authOrRevoke(op string, group SecurityGroup, perms []IPPerm) (resp *SimpleResp, err error) {
 
950
        params := makeParams(op)
 
951
        if group.Id != "" {
 
952
                params["GroupId"] = group.Id
 
953
        } else {
 
954
                params["GroupName"] = group.Name
 
955
        }
 
956
 
 
957
        for i, perm := range perms {
 
958
                prefix := "IpPermissions." + strconv.Itoa(i+1)
 
959
                params[prefix+".IpProtocol"] = perm.Protocol
 
960
                params[prefix+".FromPort"] = strconv.Itoa(perm.FromPort)
 
961
                params[prefix+".ToPort"] = strconv.Itoa(perm.ToPort)
 
962
                for j, ip := range perm.SourceIPs {
 
963
                        params[prefix+".IpRanges."+strconv.Itoa(j+1)+".CidrIp"] = ip
 
964
                }
 
965
                for j, g := range perm.SourceGroups {
 
966
                        subprefix := prefix + ".Groups." + strconv.Itoa(j+1)
 
967
                        if g.OwnerId != "" {
 
968
                                params[subprefix+".UserId"] = g.OwnerId
 
969
                        }
 
970
                        if g.Id != "" {
 
971
                                params[subprefix+".GroupId"] = g.Id
 
972
                        } else {
 
973
                                params[subprefix+".GroupName"] = g.Name
 
974
                        }
 
975
                }
 
976
        }
 
977
 
 
978
        resp = &SimpleResp{}
 
979
        err = ec2.query(params, resp)
 
980
        if err != nil {
 
981
                return nil, err
 
982
        }
 
983
        return resp, nil
 
984
}
 
985
 
 
986
// Tag represents key-value metadata used to classify and organize
 
987
// EC2 instances.
 
988
//
 
989
// See http://goo.gl/bncl3 for more details
 
990
type Tag struct {
 
991
        Key   string `xml:"key"`
 
992
        Value string `xml:"value"`
 
993
}
 
994
 
 
995
// CreateTags adds or overwrites one or more tags for the specified instance ids.
 
996
//
 
997
// See http://goo.gl/Vmkqc for more details
 
998
func (ec2 *EC2) CreateTags(instIds []string, tags []Tag) (resp *SimpleResp, err error) {
 
999
        params := makeParams("CreateTags")
 
1000
        addParamsList(params, "ResourceId", instIds)
 
1001
 
 
1002
        for j, tag := range tags {
 
1003
                params["Tag."+strconv.Itoa(j+1)+".Key"] = tag.Key
 
1004
                params["Tag."+strconv.Itoa(j+1)+".Value"] = tag.Value
 
1005
        }
 
1006
 
 
1007
        resp = &SimpleResp{}
 
1008
        err = ec2.query(params, resp)
 
1009
        if err != nil {
 
1010
                return nil, err
 
1011
        }
 
1012
        return resp, nil
 
1013
}
 
1014
 
 
1015
// Response to a StartInstances request.
 
1016
//
 
1017
// See http://goo.gl/awKeF for more details.
 
1018
type StartInstanceResp struct {
 
1019
        RequestId    string                `xml:"requestId"`
 
1020
        StateChanges []InstanceStateChange `xml:"instancesSet>item"`
 
1021
}
 
1022
 
 
1023
// Response to a StopInstances request.
 
1024
//
 
1025
// See http://goo.gl/436dJ for more details.
 
1026
type StopInstanceResp struct {
 
1027
        RequestId    string                `xml:"requestId"`
 
1028
        StateChanges []InstanceStateChange `xml:"instancesSet>item"`
 
1029
}
 
1030
 
 
1031
// StartInstances starts an Amazon EBS-backed AMI that you've previously stopped.
 
1032
//
 
1033
// See http://goo.gl/awKeF for more details.
 
1034
func (ec2 *EC2) StartInstances(ids ...string) (resp *StartInstanceResp, err error) {
 
1035
        params := makeParams("StartInstances")
 
1036
        addParamsList(params, "InstanceId", ids)
 
1037
        resp = &StartInstanceResp{}
 
1038
        err = ec2.query(params, resp)
 
1039
        if err != nil {
 
1040
                return nil, err
 
1041
        }
 
1042
        return resp, nil
 
1043
}
 
1044
 
 
1045
// StopInstances requests stopping one or more Amazon EBS-backed instances.
 
1046
//
 
1047
// See http://goo.gl/436dJ for more details.
 
1048
func (ec2 *EC2) StopInstances(ids ...string) (resp *StopInstanceResp, err error) {
 
1049
        params := makeParams("StopInstances")
 
1050
        addParamsList(params, "InstanceId", ids)
 
1051
        resp = &StopInstanceResp{}
 
1052
        err = ec2.query(params, resp)
 
1053
        if err != nil {
 
1054
                return nil, err
 
1055
        }
 
1056
        return resp, nil
 
1057
}
 
1058
 
 
1059
// RebootInstance requests a reboot of one or more instances. This operation is asynchronous;
 
1060
// it only queues a request to reboot the specified instance(s). The operation will succeed
 
1061
// if the instances are valid and belong to you.
 
1062
//
 
1063
// Requests to reboot terminated instances are ignored.
 
1064
//
 
1065
// See http://goo.gl/baoUf for more details.
 
1066
func (ec2 *EC2) RebootInstances(ids ...string) (resp *SimpleResp, err error) {
 
1067
        params := makeParams("RebootInstances")
 
1068
        addParamsList(params, "InstanceId", ids)
 
1069
        resp = &SimpleResp{}
 
1070
        err = ec2.query(params, resp)
 
1071
        if err != nil {
 
1072
                return nil, err
 
1073
        }
 
1074
        return resp, nil
 
1075
}
 
1076
 
 
1077
// ----------------------------------------------------------------------------
 
1078
// Availability zone management functions and types.
 
1079
// See http://goo.gl/ylxT4R for more details.
 
1080
 
 
1081
// AvailabilityZonesResp represents a response to a DescribeAvailabilityZones
 
1082
// request in EC2.
 
1083
type AvailabilityZonesResp struct {
 
1084
        RequestId string                 `xml:"requestId"`
 
1085
        Zones     []AvailabilityZoneInfo `xml:"availabilityZoneInfo>item"`
 
1086
}
 
1087
 
 
1088
// AvailabilityZoneInfo encapsulates details for an availability zone in EC2.
 
1089
type AvailabilityZoneInfo struct {
 
1090
        AvailabilityZone
 
1091
        State      string   `xml:"zoneState"`
 
1092
        MessageSet []string `xml:"messageSet>item"`
 
1093
}
 
1094
 
 
1095
// AvailabilityZone represents an EC2 availability zone.
 
1096
type AvailabilityZone struct {
 
1097
        Name   string `xml:"zoneName"`
 
1098
        Region string `xml:"regionName"`
 
1099
}
 
1100
 
 
1101
// AvailabilityZones returns details about availability zones in EC2.
 
1102
// The filter parameter is optional, and if provided will limit the
 
1103
// availability zones returned to those matching the given filtering
 
1104
// rules.
 
1105
//
 
1106
// See http://goo.gl/ylxT4R for more details.
 
1107
func (ec2 *EC2) AvailabilityZones(filter *Filter) (resp *AvailabilityZonesResp, err error) {
 
1108
        params := makeParams("DescribeAvailabilityZones")
 
1109
        filter.addParams(params)
 
1110
        resp = &AvailabilityZonesResp{}
 
1111
        err = ec2.query(params, resp)
 
1112
        if err != nil {
 
1113
                return nil, err
 
1114
        }
 
1115
        return
 
1116
}
 
1117
 
 
1118
// AccountAttribute holds information about an account attribute.
 
1119
//
 
1120
// See http://goo.gl/hBc28j for more details.
 
1121
type AccountAttribute struct {
 
1122
        Name   string   `xml:"attributeName"`
 
1123
        Values []string `xml:"attributeValueSet>item>attributeValue"`
 
1124
}
 
1125
 
 
1126
// AccountAttributesResp is the response to an AccountAttributes request.
 
1127
//
 
1128
// See http://goo.gl/hBc28j for more details.
 
1129
type AccountAttributesResp struct {
 
1130
        RequestId  string             `xml:"requestId"`
 
1131
        Attributes []AccountAttribute `xml:"accountAttributeSet>item"`
 
1132
}
 
1133
 
 
1134
// AccountAttributes returns the values of one or more account
 
1135
// attributes.
 
1136
//
 
1137
// See http://goo.gl/hBc28j for more details.
 
1138
func (ec2 *EC2) AccountAttributes(attrNames ...string) (*AccountAttributesResp, error) {
 
1139
        params := makeParams("DescribeAccountAttributes")
 
1140
        for i, attrName := range attrNames {
 
1141
                params["AttributeName."+strconv.Itoa(i+1)] = attrName
 
1142
        }
 
1143
 
 
1144
        resp := &AccountAttributesResp{}
 
1145
        if err := ec2.query(params, resp); err != nil {
 
1146
                return nil, err
 
1147
        }
 
1148
        return resp, nil
 
1149
}