diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json
index 48b7bba05ed..d4dcebbff70 100644
--- a/Godeps/Godeps.json
+++ b/Godeps/Godeps.json
@@ -140,11 +140,15 @@
},
{
"ImportPath": "github.com/mitchellh/goamz/aws",
- "Rev": "9cad7da945e699385c1a3e115aa255211921c9bb"
+ "Rev": "703cfb45985762869e465f37ed030ff01615ff1e"
},
{
"ImportPath": "github.com/mitchellh/goamz/ec2",
- "Rev": "9cad7da945e699385c1a3e115aa255211921c9bb"
+ "Rev": "703cfb45985762869e465f37ed030ff01615ff1e"
+ },
+ {
+ "ImportPath": "github.com/mitchellh/goamz/elb",
+ "Rev": "703cfb45985762869e465f37ed030ff01615ff1e"
},
{
"ImportPath": "github.com/mitchellh/mapstructure",
diff --git a/Godeps/_workspace/src/github.com/mitchellh/goamz/aws/aws.go b/Godeps/_workspace/src/github.com/mitchellh/goamz/aws/aws.go
index c304d5540ea..cfc42c03ab4 100644
--- a/Godeps/_workspace/src/github.com/mitchellh/goamz/aws/aws.go
+++ b/Godeps/_workspace/src/github.com/mitchellh/goamz/aws/aws.go
@@ -13,9 +13,10 @@ import (
"encoding/json"
"errors"
"fmt"
- "github.com/vaughan0/go-ini"
"io/ioutil"
"os"
+
+ "github.com/vaughan0/go-ini"
)
// Region defines the URLs where AWS services may be accessed.
@@ -123,6 +124,23 @@ var EUWest = Region{
"https://route53.amazonaws.com",
}
+var EUCentral = Region{
+ "eu-central-1",
+ "https://ec2.eu-central-1.amazonaws.com",
+ "https://s3-eu-central-1.amazonaws.com",
+ "",
+ true,
+ true,
+ "",
+ "https://sns.eu-central-1.amazonaws.com",
+ "https://sqs.eu-central-1.amazonaws.com",
+ "https://iam.amazonaws.com",
+ "https://elasticloadbalancing.eu-central-1.amazonaws.com",
+ "https://autoscaling.eu-central-1.amazonaws.com",
+ "https://rds.eu-central-1.amazonaws.com",
+ "https://route53.amazonaws.com",
+}
+
var APSoutheast = Region{
"ap-southeast-1",
"https://ec2.ap-southeast-1.amazonaws.com",
@@ -213,6 +231,7 @@ var Regions = map[string]Region{
APSoutheast.Name: APSoutheast,
APSoutheast2.Name: APSoutheast2,
EUWest.Name: EUWest,
+ EUCentral.Name: EUCentral,
USEast.Name: USEast,
USWest.Name: USWest,
USWest2.Name: USWest2,
@@ -334,13 +353,16 @@ func SharedAuth() (auth Auth, err error) {
profileName = "default"
}
- var homeDir = os.Getenv("HOME")
- if homeDir == "" {
- err = errors.New("Could not get HOME")
- return
+ var credentialsFile = os.Getenv("AWS_CREDENTIAL_FILE")
+ if credentialsFile == "" {
+ var homeDir = os.Getenv("HOME")
+ if homeDir == "" {
+ err = errors.New("Could not get HOME")
+ return
+ }
+ credentialsFile = homeDir + "/.aws/credentials"
}
- var credentialsFile = homeDir + "/.aws/credentials"
file, err := ini.LoadFile(credentialsFile)
if err != nil {
err = errors.New("Couldn't parse AWS credentials file")
diff --git a/Godeps/_workspace/src/github.com/mitchellh/goamz/ec2/ec2.go b/Godeps/_workspace/src/github.com/mitchellh/goamz/ec2/ec2.go
index 8f94ad539fb..c0c9b6712bf 100644
--- a/Godeps/_workspace/src/github.com/mitchellh/goamz/ec2/ec2.go
+++ b/Godeps/_workspace/src/github.com/mitchellh/goamz/ec2/ec2.go
@@ -127,7 +127,7 @@ type xmlErrors struct {
var timeNow = time.Now
func (ec2 *EC2) query(params map[string]string, resp interface{}) error {
- params["Version"] = "2014-05-01"
+ params["Version"] = "2014-06-15"
params["Timestamp"] = timeNow().In(time.UTC).Format(time.RFC3339)
endpoint, err := url.Parse(ec2.Region.EC2Endpoint)
if err != nil {
@@ -178,7 +178,7 @@ func buildError(r *http.Response) error {
err.RequestId = errors.RequestId
err.StatusCode = r.StatusCode
if err.Message == "" {
- err.Message = r.Status
+ err.Message = err.Code
}
return &err
}
@@ -203,29 +203,32 @@ func addBlockDeviceParams(prename string, params map[string]string, blockdevices
if k.DeviceName != "" {
params[prefix+"DeviceName"] = k.DeviceName
}
+
if k.VirtualName != "" {
params[prefix+"VirtualName"] = k.VirtualName
- }
- if k.SnapshotId != "" {
- params[prefix+"Ebs.SnapshotId"] = k.SnapshotId
- }
- if k.VolumeType != "" {
- params[prefix+"Ebs.VolumeType"] = k.VolumeType
- }
- if k.IOPS != 0 {
- params[prefix+"Ebs.Iops"] = strconv.FormatInt(k.IOPS, 10)
- }
- if k.VolumeSize != 0 {
- params[prefix+"Ebs.VolumeSize"] = strconv.FormatInt(k.VolumeSize, 10)
- }
- if k.DeleteOnTermination {
- params[prefix+"Ebs.DeleteOnTermination"] = "true"
- }
- if k.Encrypted {
- params[prefix+"Ebs.Encrypted"] = "true"
- }
- if k.NoDevice {
+ } else if k.NoDevice {
params[prefix+"NoDevice"] = ""
+ } else {
+ if k.SnapshotId != "" {
+ params[prefix+"Ebs.SnapshotId"] = k.SnapshotId
+ }
+ if k.VolumeType != "" {
+ params[prefix+"Ebs.VolumeType"] = k.VolumeType
+ }
+ if k.IOPS != 0 {
+ params[prefix+"Ebs.Iops"] = strconv.FormatInt(k.IOPS, 10)
+ }
+ if k.VolumeSize != 0 {
+ params[prefix+"Ebs.VolumeSize"] = strconv.FormatInt(k.VolumeSize, 10)
+ }
+ if k.DeleteOnTermination {
+ params[prefix+"Ebs.DeleteOnTermination"] = "true"
+ } else {
+ params[prefix+"Ebs.DeleteOnTermination"] = "false"
+ }
+ if k.Encrypted {
+ params[prefix+"Ebs.Encrypted"] = "true"
+ }
}
}
}
@@ -253,9 +256,11 @@ type RunInstances struct {
SubnetId string
AssociatePublicIpAddress bool
DisableAPITermination bool
+ EbsOptimized bool
ShutdownBehavior string
PrivateIPAddress string
BlockDevices []BlockDeviceMapping
+ Tenancy string
}
// Response to a RunInstances request.
@@ -269,6 +274,15 @@ type RunInstancesResp struct {
Instances []Instance `xml:"instancesSet>item"`
}
+// BlockDevice represents the association of a block device with an instance.
+type BlockDevice struct {
+ DeviceName string `xml:"deviceName"`
+ VolumeId string `xml:"ebs>volumeId"`
+ Status string `xml:"ebs>status"`
+ AttachTime string `xml:"ebs>attachTime"`
+ DeleteOnTermination bool `xml:"ebs>deleteOnTermination"`
+}
+
// Instance encapsulates a running instance in EC2.
//
// See http://goo.gl/OCH8a for more details.
@@ -284,6 +298,7 @@ type Instance struct {
VirtType string `xml:"virtualizationType"`
Monitoring string `xml:"monitoring>state"`
AvailZone string `xml:"placement>availabilityZone"`
+ Tenancy string `xml:"placement>tenancy"`
PlacementGroupName string `xml:"placement>groupName"`
State InstanceState `xml:"instanceState"`
Tags []Tag `xml:"tagSet>item"`
@@ -296,6 +311,8 @@ type Instance struct {
LaunchTime time.Time `xml:"launchTime"`
SourceDestCheck bool `xml:"sourceDestCheck"`
SecurityGroups []SecurityGroup `xml:"groupSet>item"`
+ EbsOptimized string `xml:"ebsOptimized"`
+ BlockDevices []BlockDevice `xml:"blockDeviceMapping>item"`
}
// RunInstances starts new instances in EC2.
@@ -350,6 +367,9 @@ func (ec2 *EC2) RunInstances(options *RunInstances) (resp *RunInstancesResp, err
if options.Monitoring {
params["Monitoring.Enabled"] = "true"
}
+ if options.Tenancy != "" {
+ params["Placement.Tenancy"] = options.Tenancy
+ }
if options.SubnetId != "" && options.AssociatePublicIpAddress {
// If we have a non-default VPC / Subnet specified, we can flag
// AssociatePublicIpAddress to get a Public IP assigned. By default these are not provided.
@@ -362,6 +382,10 @@ func (ec2 *EC2) RunInstances(options *RunInstances) (resp *RunInstancesResp, err
params["NetworkInterface.0.AssociatePublicIpAddress"] = "true"
params["NetworkInterface.0.SubnetId"] = options.SubnetId
+ if options.PrivateIPAddress != "" {
+ params["NetworkInterface.0.PrivateIpAddress"] = options.PrivateIPAddress
+ }
+
i := 1
for _, g := range options.SecurityGroups {
// We only have SecurityGroupId's on NetworkInterface's, no SecurityGroup params.
@@ -375,6 +399,10 @@ func (ec2 *EC2) RunInstances(options *RunInstances) (resp *RunInstancesResp, err
params["SubnetId"] = options.SubnetId
}
+ if options.PrivateIPAddress != "" {
+ params["PrivateIpAddress"] = options.PrivateIPAddress
+ }
+
i, j := 1, 1
for _, g := range options.SecurityGroups {
if g.Id != "" {
@@ -392,12 +420,12 @@ func (ec2 *EC2) RunInstances(options *RunInstances) (resp *RunInstancesResp, err
if options.DisableAPITermination {
params["DisableApiTermination"] = "true"
}
+ if options.EbsOptimized {
+ params["EbsOptimized"] = "true"
+ }
if options.ShutdownBehavior != "" {
params["InstanceInitiatedShutdownBehavior"] = options.ShutdownBehavior
}
- if options.PrivateIPAddress != "" {
- params["PrivateIpAddress"] = options.PrivateIPAddress
- }
addBlockDeviceParams("", params, options.BlockDevices)
resp = &RunInstancesResp{}
@@ -419,6 +447,111 @@ func clientToken() (string, error) {
return hex.EncodeToString(buf), nil
}
+// The GetConsoleOutput type encapsulates options for the respective request in EC2.
+//
+// See http://goo.gl/EY70zb for more details.
+type GetConsoleOutput struct {
+ InstanceId string
+}
+
+// Response to a GetConsoleOutput request. Note that Output is base64-encoded,
+// as in the underlying AWS API.
+//
+// See http://goo.gl/EY70zb for more details.
+type GetConsoleOutputResp struct {
+ RequestId string `xml:"requestId"`
+ InstanceId string `xml:"instanceId"`
+ Timestamp time.Time `xml:"timestamp"`
+ Output string `xml:"output"`
+}
+
+// GetConsoleOutput returns the console output for the sepcified instance. Note
+// that console output is base64-encoded, as in the underlying AWS API.
+//
+// See http://goo.gl/EY70zb for more details.
+func (ec2 *EC2) GetConsoleOutput(options *GetConsoleOutput) (resp *GetConsoleOutputResp, err error) {
+ params := makeParams("GetConsoleOutput")
+ params["InstanceId"] = options.InstanceId
+ resp = &GetConsoleOutputResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Instance events and status functions and types.
+
+// The DescribeInstanceStatus type encapsulates options for the respective request in EC2.
+//
+// See http://goo.gl/DFySJY for more details.
+type EventsSet struct {
+ Code string `xml:"code"`
+ Description string `xml:"description"`
+ NotBefore string `xml:"notBefore"`
+ NotAfter string `xml:"notAfter"`
+}
+
+type StatusDetails struct {
+ Name string `xml:"name"`
+ Status string `xml:"status"`
+ ImpairedSince string `xml:"impairedSince"`
+}
+
+type Status struct {
+ Status string `xml:"status"`
+ Details []StatusDetails `xml:"details>item"`
+}
+
+type InstanceStatusSet struct {
+ InstanceId string `xml:"instanceId"`
+ AvailabilityZone string `xml:"availabilityZone"`
+ InstanceState InstanceState `xml:"instanceState"`
+ SystemStatus Status `xml:"systemStatus"`
+ InstanceStatus Status `xml:"instanceStatus"`
+ Events []EventsSet `xml:"eventsSet>item"`
+}
+
+type DescribeInstanceStatusResp struct {
+ RequestId string `xml:"requestId"`
+ InstanceStatus []InstanceStatusSet `xml:"instanceStatusSet>item"`
+}
+
+type DescribeInstanceStatus struct {
+ InstanceIds []string
+ IncludeAllInstances bool
+ MaxResults int64
+ NextToken string
+}
+
+func (ec2 *EC2) DescribeInstanceStatus(options *DescribeInstanceStatus, filter *Filter) (resp *DescribeInstanceStatusResp, err error) {
+ params := makeParams("DescribeInstanceStatus")
+ if options.IncludeAllInstances {
+ params["IncludeAllInstances"] = "true"
+ }
+ if len(options.InstanceIds) > 0 {
+ addParamsList(params, "InstanceId", options.InstanceIds)
+ }
+ if options.MaxResults > 0 {
+ params["MaxResults"] = strconv.FormatInt(options.MaxResults, 10)
+ }
+ if options.NextToken != "" {
+ params["NextToken"] = options.NextToken
+ }
+ if filter != nil {
+ filter.addParams(params)
+ }
+
+ resp = &DescribeInstanceStatusResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+
+ return
+}
+
// ----------------------------------------------------------------------------
// Spot Instance management functions and types.
@@ -643,6 +776,61 @@ func (ec2 *EC2) CancelSpotRequests(spotrequestIds []string) (resp *CancelSpotReq
return
}
+type DescribeSpotPriceHistory struct {
+ InstanceType []string
+ ProductDescription []string
+ AvailabilityZone string
+ StartTime, EndTime time.Time
+}
+
+// Response to a DescribeSpotPriceHisotyr request.
+//
+// See http://goo.gl/3BKHj for more details.
+type DescribeSpotPriceHistoryResp struct {
+ RequestId string `xml:"requestId"`
+ History []SpotPriceHistory `xml:"spotPriceHistorySet>item"`
+}
+
+type SpotPriceHistory struct {
+ InstanceType string `xml:"instanceType"`
+ ProductDescription string `xml:"productDescription"`
+ SpotPrice string `xml:"spotPrice"`
+ Timestamp time.Time `xml:"timestamp"`
+ AvailabilityZone string `xml:"availabilityZone"`
+}
+
+// DescribeSpotPriceHistory gets the spot pricing history.
+//
+// See http://goo.gl/3BKHj for more details.
+func (ec2 *EC2) DescribeSpotPriceHistory(o *DescribeSpotPriceHistory) (resp *DescribeSpotPriceHistoryResp, err error) {
+ params := makeParams("DescribeSpotPriceHistory")
+ if o.AvailabilityZone != "" {
+ params["AvailabilityZone"] = o.AvailabilityZone
+ }
+
+ if !o.StartTime.IsZero() {
+ params["StartTime"] = o.StartTime.In(time.UTC).Format(time.RFC3339)
+ }
+ if !o.EndTime.IsZero() {
+ params["EndTime"] = o.EndTime.In(time.UTC).Format(time.RFC3339)
+ }
+
+ if len(o.InstanceType) > 0 {
+ addParamsList(params, "InstanceType", o.InstanceType)
+ }
+ if len(o.ProductDescription) > 0 {
+ addParamsList(params, "ProductDescription", o.ProductDescription)
+ }
+
+ resp = &DescribeSpotPriceHistoryResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+
+ return
+}
+
// Response to a TerminateInstances request.
//
// See http://goo.gl/3BKHj for more details.
@@ -871,6 +1059,47 @@ func (ec2 *EC2) Volumes(volIds []string, filter *Filter) (resp *VolumesResp, err
return
}
+// ----------------------------------------------------------------------------
+// Availability zone management functions and types.
+// See http://goo.gl/ylxT4R for more details.
+
+// DescribeAvailabilityZonesResp represents a response to a DescribeAvailabilityZones
+// request in EC2.
+type DescribeAvailabilityZonesResp struct {
+ RequestId string `xml:"requestId"`
+ Zones []AvailabilityZoneInfo `xml:"availabilityZoneInfo>item"`
+}
+
+// AvailabilityZoneInfo encapsulates details for an availability zone in EC2.
+type AvailabilityZoneInfo struct {
+ AvailabilityZone
+ State string `xml:"zoneState"`
+ MessageSet []string `xml:"messageSet>item"`
+}
+
+// AvailabilityZone represents an EC2 availability zone.
+type AvailabilityZone struct {
+ Name string `xml:"zoneName"`
+ Region string `xml:"regionName"`
+}
+
+// DescribeAvailabilityZones returns details about availability zones in EC2.
+// The filter parameter is optional, and if provided will limit the
+// availability zones returned to those matching the given filtering
+// rules.
+//
+// See http://goo.gl/ylxT4R for more details.
+func (ec2 *EC2) DescribeAvailabilityZones(filter *Filter) (resp *DescribeAvailabilityZonesResp, err error) {
+ params := makeParams("DescribeAvailabilityZones")
+ filter.addParams(params)
+ resp = &DescribeAvailabilityZonesResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
// ----------------------------------------------------------------------------
// ElasticIp management (for VPC)
@@ -1003,6 +1232,20 @@ func (ec2 *EC2) DisassociateAddress(id string) (resp *SimpleResp, err error) {
return
}
+// Disassociate an address from a VPC instance.
+func (ec2 *EC2) DisassociateAddressClassic(ip string) (resp *SimpleResp, err error) {
+ params := makeParams("DisassociateAddress")
+ params["PublicIp"] = ip
+
+ resp = &SimpleResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+
+ return
+}
+
// DescribeAddresses returns details about one or more
// Elastic IP Addresses. Returned addresses can be
// filtered by Public IP, Allocation ID or multiple filters
@@ -1683,6 +1926,7 @@ type SecurityGroup struct {
Name string `xml:"groupName"`
Description string `xml:"groupDescription"`
VpcId string `xml:"vpcId"`
+ Tags []Tag `xml:"tagSet>item"`
}
// SecurityGroupNames is a convenience function that
@@ -1841,6 +2085,28 @@ func (ec2 *EC2) CreateTags(resourceIds []string, tags []Tag) (resp *SimpleResp,
return resp, nil
}
+// DeleteTags deletes tags.
+func (ec2 *EC2) DeleteTags(resourceIds []string, tags []Tag) (resp *SimpleResp, err error) {
+ params := makeParams("DeleteTags")
+ addParamsList(params, "ResourceId", resourceIds)
+
+ for j, tag := range tags {
+ params["Tag."+strconv.Itoa(j+1)+".Key"] = tag.Key
+
+ if tag.Value != "" {
+ params["Tag."+strconv.Itoa(j+1)+".Value"] = tag.Value
+ }
+ }
+
+ resp = &SimpleResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+
+ return resp, nil
+}
+
type TagsResp struct {
RequestId string `xml:"requestId"`
Tags []ResourceTag `xml:"tagSet>item"`
@@ -2125,6 +2391,38 @@ type CreateSubnetResp struct {
Subnet Subnet `xml:"subnet"`
}
+// The ModifySubnetAttribute request parameters
+//
+// http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-ModifySubnetAttribute.html
+type ModifySubnetAttribute struct {
+ SubnetId string
+ MapPublicIpOnLaunch bool
+}
+
+type ModifySubnetAttributeResp struct {
+ RequestId string `xml:"requestId"`
+ Return bool `xml:"return"`
+}
+
+// The CreateNetworkAcl request parameters
+//
+// http://goo.gl/BZmCRF
+type CreateNetworkAcl struct {
+ VpcId string
+}
+
+// Response to a CreateNetworkAcl request
+type CreateNetworkAclResp struct {
+ RequestId string `xml:"requestId"`
+ NetworkAcl NetworkAcl `xml:"networkAcl"`
+}
+
+// Response to CreateNetworkAclEntry request
+type CreateNetworkAclEntryResp struct {
+ RequestId string `xml:"requestId"`
+ Return bool `xml:"return"`
+}
+
// Response to a DescribeInternetGateways request.
type InternetGatewaysResp struct {
RequestId string `xml:"requestId"`
@@ -2195,6 +2493,52 @@ type Subnet struct {
Tags []Tag `xml:"tagSet>item"`
}
+// NetworkAcl represent network acl
+type NetworkAcl struct {
+ NetworkAclId string `xml:"networkAclId"`
+ VpcId string `xml:"vpcId"`
+ Default string `xml:"default"`
+ EntrySet []NetworkAclEntry `xml:"entrySet>item"`
+ AssociationSet []NetworkAclAssociation `xml:"associationSet>item"`
+ Tags []Tag `xml:"tagSet>item"`
+}
+
+// NetworkAclAssociation
+type NetworkAclAssociation struct {
+ NetworkAclAssociationId string `xml:"networkAclAssociationId"`
+ NetworkAclId string `xml:"networkAclId"`
+ SubnetId string `xml:"subnetId"`
+}
+
+// NetworkAclEntry represent a rule within NetworkAcl
+type NetworkAclEntry struct {
+ RuleNumber int `xml:"ruleNumber"`
+ Protocol int `xml:"protocol"`
+ RuleAction string `xml:"ruleAction"`
+ Egress bool `xml:"egress"`
+ CidrBlock string `xml:"cidrBlock"`
+ IcmpCode IcmpCode `xml:"icmpTypeCode"`
+ PortRange PortRange `xml:"portRange"`
+}
+
+// IcmpCode
+type IcmpCode struct {
+ Code int `xml:"code"`
+ Type int `xml:"type"`
+}
+
+// PortRange
+type PortRange struct {
+ From int `xml:"from"`
+ To int `xml:"to"`
+}
+
+// Response to describe NetworkAcls
+type NetworkAclsResp struct {
+ RequestId string `xml:"requestId"`
+ NetworkAcls []NetworkAcl `xml:"networkAclSet>item"`
+}
+
// VPC represents a single VPC.
type VPC struct {
VpcId string `xml:"vpcId"`
@@ -2331,6 +2675,26 @@ func (ec2 *EC2) DeleteSubnet(id string) (resp *SimpleResp, err error) {
return
}
+// ModifySubnetAttribute
+//
+// http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-ModifySubnetAttribute.html
+func (ec2 *EC2) ModifySubnetAttribute(options *ModifySubnetAttribute) (resp *ModifySubnetAttributeResp, err error) {
+ params := makeParams("ModifySubnetAttribute")
+ params["SubnetId"] = options.SubnetId
+ if options.MapPublicIpOnLaunch {
+ params["MapPublicIpOnLaunch.Value"] = "true"
+ } else {
+ params["MapPublicIpOnLaunch.Value"] = "false"
+ }
+
+ resp = &ModifySubnetAttributeResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
// DescribeSubnets
//
// http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeSubnets.html
@@ -2348,6 +2712,130 @@ func (ec2 *EC2) DescribeSubnets(ids []string, filter *Filter) (resp *SubnetsResp
return
}
+// CreateNetworkAcl creates a network ACL in a VPC.
+//
+// http://goo.gl/51X7db
+func (ec2 *EC2) CreateNetworkAcl(options *CreateNetworkAcl) (resp *CreateNetworkAclResp, err error) {
+ params := makeParams("CreateNetworkAcl")
+ params["VpcId"] = options.VpcId
+
+ resp = &CreateNetworkAclResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+
+ return
+}
+
+// CreateNetworkAclEntry creates an entry (a rule) in a network ACL with the specified rule number.
+//
+// http://goo.gl/BtXhtj
+func (ec2 *EC2) CreateNetworkAclEntry(networkAclId string, options *NetworkAclEntry) (resp *CreateNetworkAclEntryResp, err error) {
+
+ params := makeParams("CreateNetworkAclEntry")
+ params["NetworkAclId"] = networkAclId
+ params["RuleNumber"] = strconv.Itoa(options.RuleNumber)
+ params["Protocol"] = strconv.Itoa(options.Protocol)
+ params["RuleAction"] = options.RuleAction
+ params["Egress"] = strconv.FormatBool(options.Egress)
+ params["CidrBlock"] = options.CidrBlock
+ if params["Protocol"] == "-1" {
+ params["Icmp.Type"] = strconv.Itoa(options.IcmpCode.Type)
+ params["Icmp.Code"] = strconv.Itoa(options.IcmpCode.Code)
+ }
+ params["PortRange.From"] = strconv.Itoa(options.PortRange.From)
+ params["PortRange.To"] = strconv.Itoa(options.PortRange.To)
+
+ resp = &CreateNetworkAclEntryResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+
+ return resp, nil
+}
+
+// NetworkAcls describes one or more of your network ACLs for given filter.
+//
+// http://goo.gl/mk9RsV
+func (ec2 *EC2) NetworkAcls(networkAclIds []string, filter *Filter) (resp *NetworkAclsResp, err error) {
+ params := makeParams("DescribeNetworkAcls")
+ addParamsList(params, "NetworkAclId", networkAclIds)
+ filter.addParams(params)
+ resp = &NetworkAclsResp{}
+ if err = ec2.query(params, resp); err != nil {
+ return nil, err
+ }
+
+ return resp, nil
+}
+
+// Response to a DeleteNetworkAcl request.
+type DeleteNetworkAclResp struct {
+ RequestId string `xml:"requestId"`
+ Return bool `xml:"return"`
+}
+
+// DeleteNetworkAcl deletes the network ACL with specified id.
+//
+// http://goo.gl/nC78Wx
+func (ec2 *EC2) DeleteNetworkAcl(id string) (resp *DeleteNetworkAclResp, err error) {
+ params := makeParams("DeleteNetworkAcl")
+ params["NetworkAclId"] = id
+
+ resp = &DeleteNetworkAclResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Response to a DeleteNetworkAclEntry request.
+type DeleteNetworkAclEntryResp struct {
+ RequestId string `xml:"requestId"`
+ Return bool `xml:"return"`
+}
+
+// DeleteNetworkAclEntry deletes the specified ingress or egress entry (rule) from the specified network ACL.
+//
+// http://goo.gl/moQbE2
+func (ec2 *EC2) DeleteNetworkAclEntry(id string, ruleNumber int, egress bool) (resp *DeleteNetworkAclEntryResp, err error) {
+ params := makeParams("DeleteNetworkAclEntry")
+ params["NetworkAclId"] = id
+ params["RuleNumber"] = strconv.Itoa(ruleNumber)
+ params["Egress"] = strconv.FormatBool(egress)
+
+ resp = &DeleteNetworkAclEntryResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+type ReplaceNetworkAclAssociationResponse struct {
+ RequestId string `xml:"requestId"`
+ NewAssociationId string `xml:"newAssociationId"`
+}
+
+// ReplaceNetworkAclAssociation changes which network ACL a subnet is associated with.
+//
+// http://goo.gl/ar0MH5
+func (ec2 *EC2) ReplaceNetworkAclAssociation(associationId string, networkAclId string) (resp *ReplaceNetworkAclAssociationResponse, err error) {
+ params := makeParams("ReplaceNetworkAclAssociation")
+ params["NetworkAclId"] = networkAclId
+ params["AssociationId"] = associationId
+
+ resp = &ReplaceNetworkAclAssociationResponse{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
// Create a new internet gateway.
func (ec2 *EC2) CreateInternetGateway(
options *CreateInternetGateway) (resp *CreateInternetGatewayResp, err error) {
diff --git a/Godeps/_workspace/src/github.com/mitchellh/goamz/ec2/ec2_test.go b/Godeps/_workspace/src/github.com/mitchellh/goamz/ec2/ec2_test.go
index 849bfe2e6bb..3ea2bdc75ed 100644
--- a/Godeps/_workspace/src/github.com/mitchellh/goamz/ec2/ec2_test.go
+++ b/Godeps/_workspace/src/github.com/mitchellh/goamz/ec2/ec2_test.go
@@ -1,12 +1,11 @@
package ec2_test
import (
- "testing"
-
"github.com/mitchellh/goamz/aws"
"github.com/mitchellh/goamz/ec2"
"github.com/mitchellh/goamz/testutil"
. "github.com/motain/gocheck"
+ "testing"
)
func Test(t *testing.T) {
@@ -95,13 +94,13 @@ func (s *S) TestRunInstancesErrorWithoutXML(c *C) {
testServer.WaitRequest()
c.Assert(resp, IsNil)
- c.Assert(err, ErrorMatches, "500 Internal Server Error")
+ c.Assert(err, ErrorMatches, "")
ec2err, ok := err.(*ec2.Error)
c.Assert(ok, Equals, true)
c.Assert(ec2err.StatusCode, Equals, 500)
c.Assert(ec2err.Code, Equals, "")
- c.Assert(ec2err.Message, Equals, "500 Internal Server Error")
+ c.Assert(ec2err.Message, Equals, "")
c.Assert(ec2err.RequestId, Equals, "")
}
@@ -114,13 +113,13 @@ func (s *S) TestRequestSpotInstancesErrorWithoutXML(c *C) {
testServer.WaitRequest()
c.Assert(resp, IsNil)
- c.Assert(err, ErrorMatches, "500 Internal Server Error")
+ c.Assert(err, ErrorMatches, "")
ec2err, ok := err.(*ec2.Error)
c.Assert(ok, Equals, true)
c.Assert(ec2err.StatusCode, Equals, 500)
c.Assert(ec2err.Code, Equals, "")
- c.Assert(ec2err.Message, Equals, "500 Internal Server Error")
+ c.Assert(ec2err.Message, Equals, "")
c.Assert(ec2err.RequestId, Equals, "")
}
@@ -136,10 +135,12 @@ func (s *S) TestRunInstancesExample(c *C) {
KernelId: "kernel-id",
RamdiskId: "ramdisk-id",
AvailZone: "zone",
+ Tenancy: "dedicated",
PlacementGroupName: "group",
Monitoring: true,
SubnetId: "subnet-id",
DisableAPITermination: true,
+ EbsOptimized: true,
ShutdownBehavior: "terminate",
PrivateIPAddress: "10.0.0.25",
BlockDevices: []ec2.BlockDeviceMapping{
@@ -168,6 +169,7 @@ func (s *S) TestRunInstancesExample(c *C) {
c.Assert(req.Form["Monitoring.Enabled"], DeepEquals, []string{"true"})
c.Assert(req.Form["SubnetId"], DeepEquals, []string{"subnet-id"})
c.Assert(req.Form["DisableApiTermination"], DeepEquals, []string{"true"})
+ c.Assert(req.Form["EbsOptimized"], DeepEquals, []string{"true"})
c.Assert(req.Form["InstanceInitiatedShutdownBehavior"], DeepEquals, []string{"terminate"})
c.Assert(req.Form["PrivateIpAddress"], DeepEquals, []string{"10.0.0.25"})
c.Assert(req.Form["BlockDeviceMapping.1.DeviceName"], DeepEquals, []string{"/dev/sdb"})
@@ -304,6 +306,7 @@ func (s *S) TestTerminateInstancesExample(c *C) {
c.Assert(req.Form["Monitoring.Enabled"], IsNil)
c.Assert(req.Form["SubnetId"], IsNil)
c.Assert(req.Form["DisableApiTermination"], IsNil)
+ c.Assert(req.Form["EbsOptimized"], IsNil)
c.Assert(req.Form["InstanceInitiatedShutdownBehavior"], IsNil)
c.Assert(req.Form["PrivateIpAddress"], IsNil)
@@ -372,6 +375,13 @@ func (s *S) TestDescribeInstancesExample1(c *C) {
c.Assert(r0i.PrivateDNSName, Equals, "domU-12-31-39-10-56-34.compute-1.internal")
c.Assert(r0i.DNSName, Equals, "ec2-174-129-165-232.compute-1.amazonaws.com")
c.Assert(r0i.AvailZone, Equals, "us-east-1b")
+
+ b0 := r0i.BlockDevices[0]
+ c.Assert(b0.DeviceName, Equals, "/dev/sda1")
+ c.Assert(b0.VolumeId, Equals, "vol-a082c1c9")
+ c.Assert(b0.Status, Equals, "attached")
+ c.Assert(b0.AttachTime, Equals, "2010-08-17T01:15:21.000Z")
+ c.Assert(b0.DeleteOnTermination, Equals, false)
}
func (s *S) TestDescribeInstancesExample2(c *C) {
@@ -1044,7 +1054,32 @@ func (s *S) TestSignatureWithEndpointPath(c *C) {
c.Assert(err, IsNil)
req := testServer.WaitRequest()
- c.Assert(req.Form["Signature"], DeepEquals, []string{"QmvgkYGn19WirCuCz/jRp3RmRgFwWR5WRkKZ5AZnyXQ="})
+ c.Assert(req.Form["Signature"], DeepEquals, []string{"tyOTQ0c0T5ujskCPTWa5ATMtv7UyErgT339cU8O2+Q8="})
+}
+
+func (s *S) TestDescribeInstanceStatusExample(c *C) {
+ testServer.Response(200, nil, DescribeInstanceStatusExample)
+ options := &ec2.DescribeInstanceStatus{}
+ resp, err := s.ec2.DescribeInstanceStatus(options, nil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeInstanceStatus"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "3be1508e-c444-4fef-89cc-0b1223c4f02fEXAMPLE")
+ c.Assert(resp.InstanceStatus[0].InstanceId, Equals, "i-1a2b3c4d")
+ c.Assert(resp.InstanceStatus[0].InstanceState.Code, Equals, 16)
+ c.Assert(resp.InstanceStatus[0].SystemStatus.Status, Equals, "impaired")
+ c.Assert(resp.InstanceStatus[0].SystemStatus.Details[0].Name, Equals, "reachability")
+ c.Assert(resp.InstanceStatus[0].SystemStatus.Details[0].Status, Equals, "failed")
+ c.Assert(resp.InstanceStatus[0].SystemStatus.Details[0].ImpairedSince, Equals, "YYYY-MM-DDTHH:MM:SS.000Z")
+ c.Assert(resp.InstanceStatus[0].InstanceStatus.Details[0].Name, Equals, "reachability")
+ c.Assert(resp.InstanceStatus[0].InstanceStatus.Details[0].Status, Equals, "failed")
+ c.Assert(resp.InstanceStatus[0].InstanceStatus.Details[0].ImpairedSince, Equals, "YYYY-MM-DDTHH:MM:SS.000Z")
+ c.Assert(resp.InstanceStatus[0].Events[0].Code, Equals, "instance-retirement")
+ c.Assert(resp.InstanceStatus[0].Events[0].Description, Equals, "The instance is running on degraded hardware")
+ c.Assert(resp.InstanceStatus[0].Events[0].NotBefore, Equals, "YYYY-MM-DDTHH:MM:SS+0000")
+ c.Assert(resp.InstanceStatus[0].Events[0].NotAfter, Equals, "YYYY-MM-DDTHH:MM:SS+0000")
}
func (s *S) TestAllocateAddressExample(c *C) {
@@ -1229,6 +1264,24 @@ func (s *S) TestCreateSubnet(c *C) {
c.Assert(resp.Subnet.AvailableIpAddressCount, Equals, 251)
}
+func (s *S) TestModifySubnetAttribute(c *C) {
+ testServer.Response(200, nil, ModifySubnetAttributeExample)
+
+ options := &ec2.ModifySubnetAttribute{
+ SubnetId: "foo",
+ MapPublicIpOnLaunch: true,
+ }
+
+ resp, err := s.ec2.ModifySubnetAttribute(options)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["SubnetId"], DeepEquals, []string{"foo"})
+ c.Assert(req.Form["MapPublicIpOnLaunch.Value"], DeepEquals, []string{"true"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+}
+
func (s *S) TestResetImageAttribute(c *C) {
testServer.Response(200, nil, ResetImageAttributeExample)
@@ -1241,3 +1294,145 @@ func (s *S) TestResetImageAttribute(c *C) {
c.Assert(err, IsNil)
c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
}
+
+func (s *S) TestDescribeAvailabilityZonesExample1(c *C) {
+ testServer.Response(200, nil, DescribeAvailabilityZonesExample1)
+
+ resp, err := s.ec2.DescribeAvailabilityZones(nil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeAvailabilityZones"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.Zones, HasLen, 4)
+
+ z0 := resp.Zones[0]
+ c.Assert(z0.Name, Equals, "us-east-1a")
+ c.Assert(z0.Region, Equals, "us-east-1")
+ c.Assert(z0.State, Equals, "available")
+ c.Assert(z0.MessageSet, HasLen, 0)
+
+ z1 := resp.Zones[1]
+ c.Assert(z1.Name, Equals, "us-east-1b")
+ c.Assert(z1.Region, Equals, "us-east-1")
+ c.Assert(z1.State, Equals, "available")
+ c.Assert(z1.MessageSet, HasLen, 0)
+
+ z2 := resp.Zones[2]
+ c.Assert(z2.Name, Equals, "us-east-1c")
+ c.Assert(z2.Region, Equals, "us-east-1")
+ c.Assert(z2.State, Equals, "available")
+ c.Assert(z2.MessageSet, HasLen, 0)
+
+ z3 := resp.Zones[3]
+ c.Assert(z3.Name, Equals, "us-east-1d")
+ c.Assert(z3.Region, Equals, "us-east-1")
+ c.Assert(z3.State, Equals, "available")
+ c.Assert(z3.MessageSet, HasLen, 0)
+}
+
+func (s *S) TestDescribeAvailabilityZonesExample2(c *C) {
+ testServer.Response(200, nil, DescribeAvailabilityZonesExample2)
+
+ resp, err := s.ec2.DescribeAvailabilityZones(nil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeAvailabilityZones"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.Zones, HasLen, 2)
+
+ z0 := resp.Zones[0]
+ c.Assert(z0.Name, Equals, "us-east-1a")
+ c.Assert(z0.Region, Equals, "us-east-1")
+ c.Assert(z0.State, Equals, "impaired")
+ c.Assert(z0.MessageSet, HasLen, 0)
+
+ z1 := resp.Zones[1]
+ c.Assert(z1.Name, Equals, "us-east-1b")
+ c.Assert(z1.Region, Equals, "us-east-1")
+ c.Assert(z1.State, Equals, "unavailable")
+ c.Assert(z1.MessageSet, DeepEquals, []string{"us-east-1b is currently down for maintenance."})
+}
+
+func (s *S) TestCreateNetworkAcl(c *C) {
+ testServer.Response(200, nil, CreateNetworkAclExample)
+
+ options := &ec2.CreateNetworkAcl{
+ VpcId: "vpc-11ad4878",
+ }
+
+ resp, err := s.ec2.CreateNetworkAcl(options)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["VpcId"], DeepEquals, []string{"vpc-11ad4878"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.NetworkAcl.VpcId, Equals, "vpc-11ad4878")
+ c.Assert(resp.NetworkAcl.NetworkAclId, Equals, "acl-5fb85d36")
+ c.Assert(resp.NetworkAcl.Default, Equals, "false")
+ c.Assert(resp.NetworkAcl.EntrySet, HasLen, 2)
+ c.Assert(resp.NetworkAcl.EntrySet[0].RuleNumber, Equals, 32767)
+ c.Assert(resp.NetworkAcl.EntrySet[0].Protocol, Equals, -1)
+ c.Assert(resp.NetworkAcl.EntrySet[0].RuleAction, Equals, "deny")
+ c.Assert(resp.NetworkAcl.EntrySet[0].Egress, Equals, true)
+ c.Assert(resp.NetworkAcl.EntrySet[0].CidrBlock, Equals, "0.0.0.0/0")
+}
+
+func (s *S) TestCreateNetworkAclEntry(c *C) {
+ testServer.Response(200, nil, CreateNetworkAclEntryRespExample)
+
+ options := &ec2.NetworkAclEntry{
+ RuleNumber: 32767,
+ Protocol: 6,
+ RuleAction: "deny",
+ Egress: true,
+ CidrBlock: "0.0.0.0/0",
+ PortRange: ec2.PortRange{
+ To: 22,
+ From: 22,
+ },
+ }
+
+ resp, err := s.ec2.CreateNetworkAclEntry("acl-11ad4878", options)
+
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Form["NetworkAclId"], DeepEquals, []string{"acl-11ad4878"})
+ c.Assert(req.Form["RuleNumber"], DeepEquals, []string{"32767"})
+ c.Assert(req.Form["Protocol"], DeepEquals, []string{"6"})
+ c.Assert(req.Form["RuleAction"], DeepEquals, []string{"deny"})
+ c.Assert(req.Form["Egress"], DeepEquals, []string{"true"})
+ c.Assert(req.Form["CidrBlock"], DeepEquals, []string{"0.0.0.0/0"})
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+}
+
+func (s *S) TestDescribeNetworkAcls(c *C) {
+ testServer.Response(200, nil, DescribeNetworkAclsExample)
+
+ filter := ec2.NewFilter()
+ filter.Add("vpc-id", "vpc-5266953b")
+
+ resp, err := s.ec2.NetworkAcls([]string{"acl-5566953c", "acl-5d659634"}, filter)
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.NetworkAcls, HasLen, 2)
+ c.Assert(resp.NetworkAcls[1].AssociationSet, HasLen, 2)
+ c.Assert(resp.NetworkAcls[1].AssociationSet[0].NetworkAclAssociationId, Equals, "aclassoc-5c659635")
+ c.Assert(resp.NetworkAcls[1].AssociationSet[0].NetworkAclId, Equals, "acl-5d659634")
+ c.Assert(resp.NetworkAcls[1].AssociationSet[0].SubnetId, Equals, "subnet-ff669596")
+}
+
+func (s *S) TestReplaceNetworkAclAssociation(c *C) {
+ testServer.Response(200, nil, ReplaceNetworkAclAssociationResponseExample)
+
+ resp, err := s.ec2.ReplaceNetworkAclAssociation("aclassoc-e5b95c8c", "acl-5fb85d36")
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.NewAssociationId, Equals, "aclassoc-17b85d7e")
+}
diff --git a/Godeps/_workspace/src/github.com/mitchellh/goamz/ec2/ec2i_test.go b/Godeps/_workspace/src/github.com/mitchellh/goamz/ec2/ec2i_test.go
index 3773041bf52..8b025dfb408 100644
--- a/Godeps/_workspace/src/github.com/mitchellh/goamz/ec2/ec2i_test.go
+++ b/Godeps/_workspace/src/github.com/mitchellh/goamz/ec2/ec2i_test.go
@@ -166,6 +166,7 @@ var allRegions = []aws.Region{
aws.USEast,
aws.USWest,
aws.EUWest,
+ aws.EUCentral,
aws.APSoutheast,
aws.APNortheast,
}
diff --git a/Godeps/_workspace/src/github.com/mitchellh/goamz/ec2/responses_test.go b/Godeps/_workspace/src/github.com/mitchellh/goamz/ec2/responses_test.go
index 0a4dbb366bb..94a681c72fd 100644
--- a/Godeps/_workspace/src/github.com/mitchellh/goamz/ec2/responses_test.go
+++ b/Godeps/_workspace/src/github.com/mitchellh/goamz/ec2/responses_test.go
@@ -766,6 +766,137 @@ var AllocateAddressExample = `
`
+// http://goo.gl/DFySJY
+var DescribeInstanceStatusExample = `
+
+ 3be1508e-c444-4fef-89cc-0b1223c4f02fEXAMPLE
+
+ -
+ i-1a2b3c4d
+ us-east-1d
+
+
16
+ running
+
+
+ impaired
+
+ -
+ reachability
+ failed
+ YYYY-MM-DDTHH:MM:SS.000Z
+
+
+
+
+ impaired
+
+ -
+ reachability
+ failed
+ YYYY-MM-DDTHH:MM:SS.000Z
+
+
+
+
+ -
+
instance-retirement
+ The instance is running on degraded hardware
+ YYYY-MM-DDTHH:MM:SS+0000
+ YYYY-MM-DDTHH:MM:SS+0000
+
+
+
+ -
+ i-2a2b3c4d
+ us-east-1d
+
+
16
+ running
+
+
+ ok
+
+ -
+ reachability
+ passed
+
+
+
+
+ ok
+
+ -
+ reachability
+ passed
+
+
+
+
+ -
+
instance-reboot
+ The instance is scheduled for a reboot
+ YYYY-MM-DDTHH:MM:SS+0000
+ YYYY-MM-DDTHH:MM:SS+0000
+
+
+
+ -
+ i-3a2b3c4d
+ us-east-1c
+
+
16
+ running
+
+
+ ok
+
+ -
+ reachability
+ passed
+
+
+
+
+ ok
+
+ -
+ reachability
+ passed
+
+
+
+
+ -
+ i-4a2b3c4d
+ us-east-1c
+
+
16
+ running
+
+
+ ok
+
+ -
+ reachability
+ passed
+
+
+
+
+ insufficient-data
+
+ -
+ reachability
+ insufficient-data
+
+
+
+
+
+
+`
+
// http://goo.gl/3Q0oCc
var ReleaseAddressExample = `
@@ -845,6 +976,14 @@ var CreateSubnetExample = `
`
+// http://goo.gl/tu2Kxm
+var ModifySubnetAttributeExample = `
+
+ 59dbff89-35bd-4eac-99ed-be587EXAMPLE
+ true
+
+`
+
// http://goo.gl/r6ZCPm
var ResetImageAttributeExample = `
@@ -852,3 +991,217 @@ var ResetImageAttributeExample = `
true
`
+
+// http://goo.gl/ylxT4R
+var DescribeAvailabilityZonesExample1 = `
+
+ 59dbff89-35bd-4eac-99ed-be587EXAMPLE
+
+ -
+ us-east-1a
+ available
+ us-east-1
+
+
+ -
+ us-east-1b
+ available
+ us-east-1
+
+
+ -
+ us-east-1c
+ available
+ us-east-1
+
+
+ -
+ us-east-1d
+ available
+ us-east-1
+
+
+
+
+`
+
+// http://goo.gl/ylxT4R
+var DescribeAvailabilityZonesExample2 = `
+
+ 59dbff89-35bd-4eac-99ed-be587EXAMPLE
+
+ -
+ us-east-1a
+ impaired
+ us-east-1
+
+
+ -
+ us-east-1b
+ unavailable
+ us-east-1
+
+
- us-east-1b is currently down for maintenance.
+
+
+
+
+`
+
+// http://goo.gl/sdomyE
+var CreateNetworkAclExample = `
+
+ 59dbff89-35bd-4eac-99ed-be587EXAMPLE
+
+ acl-5fb85d36
+ vpc-11ad4878
+ false
+
+ -
+ 32767
+ -1
+ deny
+ true
+ 0.0.0.0/0
+
+ -
+ 32767
+ -1
+ deny
+ false
+ 0.0.0.0/0
+
+
+
+
+
+
+`
+
+// http://goo.gl/6sYloC
+var CreateNetworkAclEntryRespExample = `
+
+ 59dbff89-35bd-4eac-99ed-be587EXAMPLE
+ true
+
+`
+
+// http://goo.gl/5tqceF
+var DescribeNetworkAclsExample = `
+
+ 59dbff89-35bd-4eac-99ed-be587EXAMPLE
+
+ -
+ acl-5566953c
+ vpc-5266953b
+ true
+
+
-
+ 100
+ -1
+ allow
+ true
+ 0.0.0.0/0
+
+ -
+ 32767
+ -1
+ deny
+ true
+ 0.0.0.0/0
+
+ -
+ 100
+ -1
+ allow
+ false
+ 0.0.0.0/0
+
+ -
+ 32767
+ -1
+ deny
+ false
+ 0.0.0.0/0
+
+
+
+
+
+ -
+ acl-5d659634
+ vpc-5266953b
+ false
+
+
-
+ 110
+ 6
+ allow
+ true
+ 0.0.0.0/0
+
+ 49152
+ 65535
+
+
+ -
+ 32767
+ -1
+ deny
+ true
+ 0.0.0.0/0
+
+ -
+ 110
+ 6
+ allow
+ false
+ 0.0.0.0/0
+
+ 80
+ 80
+
+
+ -
+ 120
+ 6
+ allow
+ false
+ 0.0.0.0/0
+
+ 443
+ 443
+
+
+ -
+ 32767
+ -1
+ deny
+ false
+ 0.0.0.0/0
+
+
+
+ -
+ aclassoc-5c659635
+ acl-5d659634
+ subnet-ff669596
+
+ -
+ aclassoc-c26596ab
+ acl-5d659634
+ subnet-f0669599
+
+
+
+
+
+
+`
+
+var ReplaceNetworkAclAssociationResponseExample = `
+
+ 59dbff89-35bd-4eac-99ed-be587EXAMPLE
+ aclassoc-17b85d7e
+
+`
diff --git a/Godeps/_workspace/src/github.com/mitchellh/goamz/elb/elb.go b/Godeps/_workspace/src/github.com/mitchellh/goamz/elb/elb.go
new file mode 100644
index 00000000000..e0d53f3879c
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/mitchellh/goamz/elb/elb.go
@@ -0,0 +1,575 @@
+// The elb package provides types and functions for interaction with the AWS
+// Elastic Load Balancing service (ELB)
+package elb
+
+import (
+ "encoding/xml"
+ "net/http"
+ "net/url"
+ "strconv"
+ "time"
+
+ "github.com/mitchellh/goamz/aws"
+)
+
+// The ELB type encapsulates operations operations with the elb endpoint.
+type ELB struct {
+ aws.Auth
+ aws.Region
+ httpClient *http.Client
+}
+
+const APIVersion = "2012-06-01"
+
+// New creates a new ELB instance.
+func New(auth aws.Auth, region aws.Region) *ELB {
+ return NewWithClient(auth, region, aws.RetryingClient)
+}
+
+func NewWithClient(auth aws.Auth, region aws.Region, httpClient *http.Client) *ELB {
+ return &ELB{auth, region, httpClient}
+}
+
+func (elb *ELB) query(params map[string]string, resp interface{}) error {
+ params["Version"] = APIVersion
+ params["Timestamp"] = time.Now().In(time.UTC).Format(time.RFC3339)
+
+ endpoint, err := url.Parse(elb.Region.ELBEndpoint)
+ if err != nil {
+ return err
+ }
+
+ sign(elb.Auth, "GET", "/", params, endpoint.Host)
+ endpoint.RawQuery = multimap(params).Encode()
+ r, err := elb.httpClient.Get(endpoint.String())
+
+ if err != nil {
+ return err
+ }
+ defer r.Body.Close()
+ if r.StatusCode > 200 {
+ return buildError(r)
+ }
+
+ decoder := xml.NewDecoder(r.Body)
+ decodedBody := decoder.Decode(resp)
+
+ return decodedBody
+}
+
+func buildError(r *http.Response) error {
+ var (
+ err Error
+ errors xmlErrors
+ )
+ xml.NewDecoder(r.Body).Decode(&errors)
+ if len(errors.Errors) > 0 {
+ err = errors.Errors[0]
+ }
+ err.StatusCode = r.StatusCode
+ if err.Message == "" {
+ err.Message = r.Status
+ }
+ return &err
+}
+
+func multimap(p map[string]string) url.Values {
+ q := make(url.Values, len(p))
+ for k, v := range p {
+ q[k] = []string{v}
+ }
+ return q
+}
+
+func makeParams(action string) map[string]string {
+ params := make(map[string]string)
+ params["Action"] = action
+ return params
+}
+
+// ----------------------------------------------------------------------------
+// ELB objects
+
+// A listener attaches to an elb
+type Listener struct {
+ InstancePort int64 `xml:"Listener>InstancePort"`
+ InstanceProtocol string `xml:"Listener>InstanceProtocol"`
+ SSLCertificateId string `xml:"Listener>SSLCertificateId"`
+ LoadBalancerPort int64 `xml:"Listener>LoadBalancerPort"`
+ Protocol string `xml:"Listener>Protocol"`
+}
+
+// An Instance attaches to an elb
+type Instance struct {
+ InstanceId string `xml:"InstanceId"`
+}
+
+// A tag attached to an elb
+type Tag struct {
+ Key string `xml:"Key"`
+ Value string `xml:"Value"`
+}
+
+// An InstanceState from an elb health query
+type InstanceState struct {
+ InstanceId string `xml:"InstanceId"`
+ Description string `xml:"Description"`
+ State string `xml:"State"`
+ ReasonCode string `xml:"ReasonCode"`
+}
+
+// ----------------------------------------------------------------------------
+// AddTags
+
+type AddTags struct {
+ LoadBalancerNames []string
+ Tags []Tag
+}
+
+type AddTagsResp struct {
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+func (elb *ELB) AddTags(options *AddTags) (resp *AddTagsResp, err error) {
+ params := makeParams("AddTags")
+
+ for i, v := range options.LoadBalancerNames {
+ params["LoadBalancerNames.member."+strconv.Itoa(i+1)] = v
+ }
+
+ for i, v := range options.Tags {
+ params["Tags.member."+strconv.Itoa(i+1)+".Key"] = v.Key
+ params["Tags.member."+strconv.Itoa(i+1)+".Value"] = v.Value
+ }
+
+ resp = &AddTagsResp{}
+
+ err = elb.query(params, resp)
+
+ return resp, err
+}
+
+// ----------------------------------------------------------------------------
+// RemoveTags
+
+type RemoveTags struct {
+ LoadBalancerNames []string
+ TagKeys []string
+}
+
+type RemoveTagsResp struct {
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+func (elb *ELB) RemoveTags(options *RemoveTags) (resp *RemoveTagsResp, err error) {
+ params := makeParams("RemoveTags")
+
+ for i, v := range options.LoadBalancerNames {
+ params["LoadBalancerNames.member."+strconv.Itoa(i+1)] = v
+ }
+
+ for i, v := range options.TagKeys {
+ params["Tags.member."+strconv.Itoa(i+1)+".Key"] = v
+ }
+
+ resp = &RemoveTagsResp{}
+
+ err = elb.query(params, resp)
+
+ return resp, err
+}
+
+// ----------------------------------------------------------------------------
+// Create
+
+// The CreateLoadBalancer request parameters
+type CreateLoadBalancer struct {
+ AvailZone []string
+ Listeners []Listener
+ LoadBalancerName string
+ Internal bool // true for vpc elbs
+ SecurityGroups []string
+ Subnets []string
+ Tags []Tag
+}
+
+type CreateLoadBalancerResp struct {
+ DNSName string `xml:"CreateLoadBalancerResult>DNSName"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+func (elb *ELB) CreateLoadBalancer(options *CreateLoadBalancer) (resp *CreateLoadBalancerResp, err error) {
+ params := makeParams("CreateLoadBalancer")
+
+ params["LoadBalancerName"] = options.LoadBalancerName
+
+ for i, v := range options.AvailZone {
+ params["AvailabilityZones.member."+strconv.Itoa(i+1)] = v
+ }
+
+ for i, v := range options.SecurityGroups {
+ params["SecurityGroups.member."+strconv.Itoa(i+1)] = v
+ }
+
+ for i, v := range options.Subnets {
+ params["Subnets.member."+strconv.Itoa(i+1)] = v
+ }
+
+ for i, v := range options.Listeners {
+ params["Listeners.member."+strconv.Itoa(i+1)+".LoadBalancerPort"] = strconv.FormatInt(v.LoadBalancerPort, 10)
+ params["Listeners.member."+strconv.Itoa(i+1)+".InstancePort"] = strconv.FormatInt(v.InstancePort, 10)
+ params["Listeners.member."+strconv.Itoa(i+1)+".Protocol"] = v.Protocol
+ params["Listeners.member."+strconv.Itoa(i+1)+".InstanceProtocol"] = v.InstanceProtocol
+ params["Listeners.member."+strconv.Itoa(i+1)+".SSLCertificateId"] = v.SSLCertificateId
+ }
+
+ for i, v := range options.Tags {
+ params["Tags.member."+strconv.Itoa(i+1)+".Key"] = v.Key
+ params["Tags.member."+strconv.Itoa(i+1)+".Value"] = v.Value
+ }
+
+ if options.Internal {
+ params["Scheme"] = "internal"
+ }
+
+ resp = &CreateLoadBalancerResp{}
+
+ err = elb.query(params, resp)
+
+ if err != nil {
+ resp = nil
+ }
+
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Destroy
+
+// The DestroyLoadBalancer request parameters
+type DeleteLoadBalancer struct {
+ LoadBalancerName string
+}
+
+func (elb *ELB) DeleteLoadBalancer(options *DeleteLoadBalancer) (resp *SimpleResp, err error) {
+ params := makeParams("DeleteLoadBalancer")
+
+ params["LoadBalancerName"] = options.LoadBalancerName
+
+ resp = &SimpleResp{}
+
+ err = elb.query(params, resp)
+
+ if err != nil {
+ resp = nil
+ }
+
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Describe
+
+// An individual load balancer
+type LoadBalancer struct {
+ LoadBalancerName string `xml:"LoadBalancerName"`
+ Listeners []Listener `xml:"ListenerDescriptions>member"`
+ Instances []Instance `xml:"Instances>member"`
+ HealthCheck HealthCheck `xml:"HealthCheck"`
+ AvailabilityZones []string `xml:"AvailabilityZones>member"`
+ HostedZoneNameID string `xml:"CanonicalHostedZoneNameID"`
+ DNSName string `xml:"DNSName"`
+ SecurityGroups []string `xml:"SecurityGroups>member"`
+ Scheme string `xml:"Scheme"`
+ Subnets []string `xml:"Subnets>member"`
+}
+
+// DescribeLoadBalancer request params
+type DescribeLoadBalancer struct {
+ Names []string
+}
+
+type DescribeLoadBalancersResp struct {
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+ LoadBalancers []LoadBalancer `xml:"DescribeLoadBalancersResult>LoadBalancerDescriptions>member"`
+}
+
+func (elb *ELB) DescribeLoadBalancers(options *DescribeLoadBalancer) (resp *DescribeLoadBalancersResp, err error) {
+ params := makeParams("DescribeLoadBalancers")
+
+ for i, v := range options.Names {
+ params["LoadBalancerNames.member."+strconv.Itoa(i+1)] = v
+ }
+
+ resp = &DescribeLoadBalancersResp{}
+
+ err = elb.query(params, resp)
+
+ if err != nil {
+ resp = nil
+ }
+
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Attributes
+
+type AccessLog struct {
+ EmitInterval int64
+ Enabled bool
+ S3BucketName string
+ S3BucketPrefix string
+}
+
+type ConnectionDraining struct {
+ Enabled bool
+ Timeout int64
+}
+
+type LoadBalancerAttributes struct {
+ CrossZoneLoadBalancingEnabled bool
+ ConnectionSettingsIdleTimeout int64
+ ConnectionDraining ConnectionDraining
+ AccessLog AccessLog
+}
+
+type ModifyLoadBalancerAttributes struct {
+ LoadBalancerName string
+ LoadBalancerAttributes LoadBalancerAttributes
+}
+
+func (elb *ELB) ModifyLoadBalancerAttributes(options *ModifyLoadBalancerAttributes) (resp *SimpleResp, err error) {
+ params := makeParams("ModifyLoadBalancerAttributes")
+
+ params["LoadBalancerName"] = options.LoadBalancerName
+ params["LoadBalancerAttributes.CrossZoneLoadBalancing.Enabled"] = strconv.FormatBool(options.LoadBalancerAttributes.CrossZoneLoadBalancingEnabled)
+ if options.LoadBalancerAttributes.ConnectionSettingsIdleTimeout > 0 {
+ params["LoadBalancerAttributes.ConnectionSettings.IdleTimeout"] = strconv.Itoa(int(options.LoadBalancerAttributes.ConnectionSettingsIdleTimeout))
+ }
+ if options.LoadBalancerAttributes.ConnectionDraining.Timeout > 0 {
+ params["LoadBalancerAttributes.ConnectionDraining.Timeout"] = strconv.Itoa(int(options.LoadBalancerAttributes.ConnectionDraining.Timeout))
+ }
+ params["LoadBalancerAttributes.ConnectionDraining.Enabled"] = strconv.FormatBool(options.LoadBalancerAttributes.ConnectionDraining.Enabled)
+ params["LoadBalancerAttributes.AccessLog.Enabled"] = strconv.FormatBool(options.LoadBalancerAttributes.AccessLog.Enabled)
+ if options.LoadBalancerAttributes.AccessLog.Enabled {
+ params["LoadBalancerAttributes.AccessLog.EmitInterval"] = strconv.Itoa(int(options.LoadBalancerAttributes.AccessLog.EmitInterval))
+ params["LoadBalancerAttributes.AccessLog.S3BucketName"] = options.LoadBalancerAttributes.AccessLog.S3BucketName
+ params["LoadBalancerAttributes.AccessLog.S3BucketPrefix"] = options.LoadBalancerAttributes.AccessLog.S3BucketPrefix
+ }
+
+ resp = &SimpleResp{}
+
+ err = elb.query(params, resp)
+
+ if err != nil {
+ resp = nil
+ }
+
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Instance Registration / deregistration
+
+// The RegisterInstancesWithLoadBalancer request parameters
+type RegisterInstancesWithLoadBalancer struct {
+ LoadBalancerName string
+ Instances []string
+}
+
+type RegisterInstancesWithLoadBalancerResp struct {
+ Instances []Instance `xml:"RegisterInstancesWithLoadBalancerResult>Instances>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+func (elb *ELB) RegisterInstancesWithLoadBalancer(options *RegisterInstancesWithLoadBalancer) (resp *RegisterInstancesWithLoadBalancerResp, err error) {
+ params := makeParams("RegisterInstancesWithLoadBalancer")
+
+ params["LoadBalancerName"] = options.LoadBalancerName
+
+ for i, v := range options.Instances {
+ params["Instances.member."+strconv.Itoa(i+1)+".InstanceId"] = v
+ }
+
+ resp = &RegisterInstancesWithLoadBalancerResp{}
+
+ err = elb.query(params, resp)
+
+ if err != nil {
+ resp = nil
+ }
+
+ return
+}
+
+// The DeregisterInstancesFromLoadBalancer request parameters
+type DeregisterInstancesFromLoadBalancer struct {
+ LoadBalancerName string
+ Instances []string
+}
+
+type DeregisterInstancesFromLoadBalancerResp struct {
+ Instances []Instance `xml:"DeregisterInstancesFromLoadBalancerResult>Instances>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+func (elb *ELB) DeregisterInstancesFromLoadBalancer(options *DeregisterInstancesFromLoadBalancer) (resp *DeregisterInstancesFromLoadBalancerResp, err error) {
+ params := makeParams("DeregisterInstancesFromLoadBalancer")
+
+ params["LoadBalancerName"] = options.LoadBalancerName
+
+ for i, v := range options.Instances {
+ params["Instances.member."+strconv.Itoa(i+1)+".InstanceId"] = v
+ }
+
+ resp = &DeregisterInstancesFromLoadBalancerResp{}
+
+ err = elb.query(params, resp)
+
+ if err != nil {
+ resp = nil
+ }
+
+ return
+}
+
+// ----------------------------------------------------------------------------
+// DescribeTags
+
+type DescribeTags struct {
+ LoadBalancerNames []string
+}
+
+type LoadBalancerTag struct {
+ Tags []Tag `xml:"Tags>member"`
+ LoadBalancerName string `xml:"LoadBalancerName"`
+}
+
+type DescribeTagsResp struct {
+ LoadBalancerTags []LoadBalancerTag `xml:"DescribeTagsResult>TagDescriptions>member"`
+ NextToken string `xml:"DescribeTagsResult>NextToken"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+func (elb *ELB) DescribeTags(options *DescribeTags) (resp *DescribeTagsResp, err error) {
+ params := makeParams("DescribeTags")
+
+ for i, v := range options.LoadBalancerNames {
+ params["LoadBalancerNames.member."+strconv.Itoa(i+1)] = v
+ }
+
+ resp = &DescribeTagsResp{}
+
+ err = elb.query(params, resp)
+
+ if err != nil {
+ resp = nil
+ }
+
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Health Checks
+
+type HealthCheck struct {
+ HealthyThreshold int64 `xml:"HealthyThreshold"`
+ UnhealthyThreshold int64 `xml:"UnhealthyThreshold"`
+ Interval int64 `xml:"Interval"`
+ Target string `xml:"Target"`
+ Timeout int64 `xml:"Timeout"`
+}
+
+type ConfigureHealthCheck struct {
+ LoadBalancerName string
+ Check HealthCheck
+}
+
+type ConfigureHealthCheckResp struct {
+ Check HealthCheck `xml:"ConfigureHealthCheckResult>HealthCheck"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+func (elb *ELB) ConfigureHealthCheck(options *ConfigureHealthCheck) (resp *ConfigureHealthCheckResp, err error) {
+ params := makeParams("ConfigureHealthCheck")
+
+ params["LoadBalancerName"] = options.LoadBalancerName
+ params["HealthCheck.HealthyThreshold"] = strconv.Itoa(int(options.Check.HealthyThreshold))
+ params["HealthCheck.UnhealthyThreshold"] = strconv.Itoa(int(options.Check.UnhealthyThreshold))
+ params["HealthCheck.Interval"] = strconv.Itoa(int(options.Check.Interval))
+ params["HealthCheck.Target"] = options.Check.Target
+ params["HealthCheck.Timeout"] = strconv.Itoa(int(options.Check.Timeout))
+
+ resp = &ConfigureHealthCheckResp{}
+
+ err = elb.query(params, resp)
+
+ if err != nil {
+ resp = nil
+ }
+
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Instance Health
+
+// The DescribeInstanceHealth request parameters
+type DescribeInstanceHealth struct {
+ LoadBalancerName string
+}
+
+type DescribeInstanceHealthResp struct {
+ InstanceStates []InstanceState `xml:"DescribeInstanceHealthResult>InstanceStates>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+func (elb *ELB) DescribeInstanceHealth(options *DescribeInstanceHealth) (resp *DescribeInstanceHealthResp, err error) {
+ params := makeParams("DescribeInstanceHealth")
+
+ params["LoadBalancerName"] = options.LoadBalancerName
+
+ resp = &DescribeInstanceHealthResp{}
+
+ err = elb.query(params, resp)
+
+ if err != nil {
+ resp = nil
+ }
+
+ return
+}
+
+// Responses
+
+type SimpleResp struct {
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+type xmlErrors struct {
+ Errors []Error `xml:"Error"`
+}
+
+// Error encapsulates an elb error.
+type Error struct {
+ // HTTP status code of the error.
+ StatusCode int
+
+ // AWS code of the error.
+ Code string
+
+ // Message explaining the error.
+ Message string
+}
+
+func (e *Error) Error() string {
+ var prefix string
+ if e.Code != "" {
+ prefix = e.Code + ": "
+ }
+ if prefix == "" && e.StatusCode > 0 {
+ prefix = strconv.Itoa(e.StatusCode) + ": "
+ }
+ return prefix + e.Message
+}
diff --git a/Godeps/_workspace/src/github.com/mitchellh/goamz/elb/elb_test.go b/Godeps/_workspace/src/github.com/mitchellh/goamz/elb/elb_test.go
new file mode 100644
index 00000000000..d0a5caab618
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/mitchellh/goamz/elb/elb_test.go
@@ -0,0 +1,235 @@
+package elb_test
+
+import (
+ "github.com/mitchellh/goamz/aws"
+ "github.com/mitchellh/goamz/elb"
+ "github.com/mitchellh/goamz/testutil"
+ . "github.com/motain/gocheck"
+ "testing"
+)
+
+func Test(t *testing.T) {
+ TestingT(t)
+}
+
+type S struct {
+ elb *elb.ELB
+}
+
+var _ = Suite(&S{})
+
+var testServer = testutil.NewHTTPServer()
+
+func (s *S) SetUpSuite(c *C) {
+ testServer.Start()
+ auth := aws.Auth{"abc", "123", ""}
+ s.elb = elb.NewWithClient(auth, aws.Region{ELBEndpoint: testServer.URL}, testutil.DefaultClient)
+}
+
+func (s *S) TearDownTest(c *C) {
+ testServer.Flush()
+}
+
+func (s *S) TestAddTags(c *C) {
+ testServer.Response(200, nil, AddTagsExample)
+
+ options := elb.AddTags{
+ LoadBalancerNames: []string{"foobar"},
+ Tags: []elb.Tag{
+ {
+ Key: "hello",
+ Value: "world",
+ },
+ },
+ }
+
+ resp, err := s.elb.AddTags(&options)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Form["Action"], DeepEquals, []string{"AddTags"})
+ c.Assert(req.Form["LoadBalancerNames.member.1"], DeepEquals, []string{"foobar"})
+ c.Assert(req.Form["Tags.member.1.Key"], DeepEquals, []string{"hello"})
+ c.Assert(req.Form["Tags.member.1.Value"], DeepEquals, []string{"world"})
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "360e81f7-1100-11e4-b6ed-0f30EXAMPLE")
+}
+
+func (s *S) TestRemoveTags(c *C) {
+ testServer.Response(200, nil, RemoveTagsExample)
+
+ options := elb.RemoveTags{
+ LoadBalancerNames: []string{"foobar"},
+ TagKeys: []string{"hello"},
+ }
+
+ resp, err := s.elb.RemoveTags(&options)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Form["Action"], DeepEquals, []string{"RemoveTags"})
+ c.Assert(req.Form["LoadBalancerNames.member.1"], DeepEquals, []string{"foobar"})
+ c.Assert(req.Form["Tags.member.1.Key"], DeepEquals, []string{"hello"})
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "83c88b9d-12b7-11e3-8b82-87b12EXAMPLE")
+}
+
+func (s *S) TestCreateLoadBalancer(c *C) {
+ testServer.Response(200, nil, CreateLoadBalancerExample)
+
+ options := elb.CreateLoadBalancer{
+ AvailZone: []string{"us-east-1a"},
+ Listeners: []elb.Listener{elb.Listener{
+ InstancePort: 80,
+ InstanceProtocol: "http",
+ SSLCertificateId: "needToAddASSLCertToYourAWSAccount",
+ LoadBalancerPort: 80,
+ Protocol: "http",
+ },
+ },
+ LoadBalancerName: "foobar",
+ Internal: false,
+ SecurityGroups: []string{"sg1"},
+ Subnets: []string{"sn1"},
+ }
+
+ resp, err := s.elb.CreateLoadBalancer(&options)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Form["Action"], DeepEquals, []string{"CreateLoadBalancer"})
+ c.Assert(req.Form["LoadBalancerName"], DeepEquals, []string{"foobar"})
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "1549581b-12b7-11e3-895e-1334aEXAMPLE")
+}
+
+func (s *S) TestDeleteLoadBalancer(c *C) {
+ testServer.Response(200, nil, DeleteLoadBalancerExample)
+
+ options := elb.DeleteLoadBalancer{
+ LoadBalancerName: "foobar",
+ }
+
+ resp, err := s.elb.DeleteLoadBalancer(&options)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DeleteLoadBalancer"})
+ c.Assert(req.Form["LoadBalancerName"], DeepEquals, []string{"foobar"})
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "1549581b-12b7-11e3-895e-1334aEXAMPLE")
+}
+
+func (s *S) TestDescribeLoadBalancers(c *C) {
+ testServer.Response(200, nil, DescribeLoadBalancersExample)
+
+ options := elb.DescribeLoadBalancer{
+ Names: []string{"foobar"},
+ }
+
+ resp, err := s.elb.DescribeLoadBalancers(&options)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeLoadBalancers"})
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "83c88b9d-12b7-11e3-8b82-87b12EXAMPLE")
+ c.Assert(resp.LoadBalancers[0].LoadBalancerName, Equals, "MyLoadBalancer")
+ c.Assert(resp.LoadBalancers[0].Listeners[0].Protocol, Equals, "HTTP")
+ c.Assert(resp.LoadBalancers[0].Instances[0].InstanceId, Equals, "i-e4cbe38d")
+ c.Assert(resp.LoadBalancers[0].AvailabilityZones[0].AvailabilityZone, Equals, "us-east-1a")
+ c.Assert(resp.LoadBalancers[0].Scheme, Equals, "internet-facing")
+ c.Assert(resp.LoadBalancers[0].DNSName, Equals, "MyLoadBalancer-123456789.us-east-1.elb.amazonaws.com")
+ c.Assert(resp.LoadBalancers[0].HealthCheck.HealthyThreshold, Equals, int64(2))
+ c.Assert(resp.LoadBalancers[0].HealthCheck.UnhealthyThreshold, Equals, int64(10))
+ c.Assert(resp.LoadBalancers[0].HealthCheck.Interval, Equals, int64(90))
+ c.Assert(resp.LoadBalancers[0].HealthCheck.Target, Equals, "HTTP:80/")
+ c.Assert(resp.LoadBalancers[0].HealthCheck.Timeout, Equals, int64(60))
+}
+
+func (s *S) TestRegisterInstancesWithLoadBalancer(c *C) {
+ testServer.Response(200, nil, RegisterInstancesWithLoadBalancerExample)
+
+ options := elb.RegisterInstancesWithLoadBalancer{
+ LoadBalancerName: "foobar",
+ Instances: []string{"instance-1", "instance-2"},
+ }
+
+ resp, err := s.elb.RegisterInstancesWithLoadBalancer(&options)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Form["Action"], DeepEquals, []string{"RegisterInstancesWithLoadBalancer"})
+ c.Assert(req.Form["LoadBalancerName"], DeepEquals, []string{"foobar"})
+ c.Assert(req.Form["Instances.member.1.InstanceId"], DeepEquals, []string{"instance-1"})
+ c.Assert(req.Form["Instances.member.2.InstanceId"], DeepEquals, []string{"instance-2"})
+ c.Assert(err, IsNil)
+
+ c.Assert(resp.Instances[0].InstanceId, Equals, "i-315b7e51")
+ c.Assert(resp.RequestId, Equals, "83c88b9d-12b7-11e3-8b82-87b12EXAMPLE")
+}
+
+func (s *S) TestDeregisterInstancesFromLoadBalancer(c *C) {
+ testServer.Response(200, nil, DeregisterInstancesFromLoadBalancerExample)
+
+ options := elb.DeregisterInstancesFromLoadBalancer{
+ LoadBalancerName: "foobar",
+ Instances: []string{"instance-1", "instance-2"},
+ }
+
+ resp, err := s.elb.DeregisterInstancesFromLoadBalancer(&options)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DeregisterInstancesFromLoadBalancer"})
+ c.Assert(req.Form["LoadBalancerName"], DeepEquals, []string{"foobar"})
+ c.Assert(req.Form["Instances.member.1.InstanceId"], DeepEquals, []string{"instance-1"})
+ c.Assert(req.Form["Instances.member.2.InstanceId"], DeepEquals, []string{"instance-2"})
+ c.Assert(err, IsNil)
+
+ c.Assert(resp.Instances[0].InstanceId, Equals, "i-6ec63d59")
+ c.Assert(resp.RequestId, Equals, "83c88b9d-12b7-11e3-8b82-87b12EXAMPLE")
+}
+
+func (s *S) TestConfigureHealthCheck(c *C) {
+ testServer.Response(200, nil, ConfigureHealthCheckExample)
+
+ options := elb.ConfigureHealthCheck{
+ LoadBalancerName: "foobar",
+ Check: elb.HealthCheck{
+ HealthyThreshold: 2,
+ UnhealthyThreshold: 2,
+ Interval: 30,
+ Target: "HTTP:80/ping",
+ Timeout: 3,
+ },
+ }
+
+ resp, err := s.elb.ConfigureHealthCheck(&options)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Form["Action"], DeepEquals, []string{"ConfigureHealthCheck"})
+ c.Assert(req.Form["LoadBalancerName"], DeepEquals, []string{"foobar"})
+ c.Assert(err, IsNil)
+
+ c.Assert(resp.Check.HealthyThreshold, Equals, int64(2))
+ c.Assert(resp.Check.UnhealthyThreshold, Equals, int64(2))
+ c.Assert(resp.Check.Interval, Equals, int64(30))
+ c.Assert(resp.Check.Target, Equals, "HTTP:80/ping")
+ c.Assert(resp.Check.Timeout, Equals, int64(3))
+ c.Assert(resp.RequestId, Equals, "83c88b9d-12b7-11e3-8b82-87b12EXAMPLE")
+}
+
+func (s *S) TestDescribeInstanceHealth(c *C) {
+ testServer.Response(200, nil, DescribeInstanceHealthExample)
+
+ options := elb.DescribeInstanceHealth{
+ LoadBalancerName: "foobar",
+ }
+
+ resp, err := s.elb.DescribeInstanceHealth(&options)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeInstanceHealth"})
+ c.Assert(req.Form["LoadBalancerName"], DeepEquals, []string{"foobar"})
+ c.Assert(err, IsNil)
+
+ c.Assert(resp.InstanceStates[0].InstanceId, Equals, "i-90d8c2a5")
+ c.Assert(resp.InstanceStates[0].State, Equals, "InService")
+ c.Assert(resp.InstanceStates[1].InstanceId, Equals, "i-06ea3e60")
+ c.Assert(resp.InstanceStates[1].State, Equals, "OutOfService")
+ c.Assert(resp.RequestId, Equals, "1549581b-12b7-11e3-895e-1334aEXAMPLE")
+}
diff --git a/Godeps/_workspace/src/github.com/mitchellh/goamz/elb/responses_test.go b/Godeps/_workspace/src/github.com/mitchellh/goamz/elb/responses_test.go
new file mode 100644
index 00000000000..77ae390cec7
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/mitchellh/goamz/elb/responses_test.go
@@ -0,0 +1,182 @@
+package elb_test
+
+var ErrorDump = `
+
+UnsupportedOperation
+
+0503f4e9-bbd6-483c-b54f-c4ae9f3b30f4
+`
+
+// http://goo.gl/OkMdtJ
+var AddTagsExample = `
+
+
+
+ 360e81f7-1100-11e4-b6ed-0f30EXAMPLE
+
+
+`
+
+// http://goo.gl/nT2E89
+var RemoveTagsExample = `
+
+
+
+ 83c88b9d-12b7-11e3-8b82-87b12EXAMPLE
+
+
+`
+
+// http://goo.gl/gQRD2H
+var CreateLoadBalancerExample = `
+
+
+ MyLoadBalancer-1234567890.us-east-1.elb.amazonaws.com
+
+
+ 1549581b-12b7-11e3-895e-1334aEXAMPLE
+
+
+`
+
+// http://goo.gl/GLZeBN
+var DeleteLoadBalancerExample = `
+
+
+ 1549581b-12b7-11e3-895e-1334aEXAMPLE
+
+
+`
+
+// http://goo.gl/8UgpQ8
+var DescribeLoadBalancersExample = `
+
+
+
+
+
+ MyLoadBalancer
+ 2013-05-24T21:15:31.280Z
+
+ 90
+ HTTP:80/
+ 2
+ 60
+ 10
+
+
+
+
+
+ HTTP
+ 80
+ HTTP
+ needToAddASSLCertToYourAWSAccount
+ 80
+
+
+
+
+
+ i-e4cbe38d
+
+
+
+
+
+
+
+
+ us-east-1a
+
+ ZZZZZZZZZZZ123X
+ MyLoadBalancer-123456789.us-east-1.elb.amazonaws.com
+ internet-facing
+
+ amazon-elb
+ amazon-elb-sg
+
+ MyLoadBalancer-123456789.us-east-1.elb.amazonaws.com
+
+
+
+
+
+
+ 83c88b9d-12b7-11e3-8b82-87b12EXAMPLE
+
+
+`
+
+// http://goo.gl/Uz1N66
+var RegisterInstancesWithLoadBalancerExample = `
+
+
+
+
+ i-315b7e51
+
+
+
+
+ 83c88b9d-12b7-11e3-8b82-87b12EXAMPLE
+
+
+ `
+
+// http://goo.gl/5OMv62
+var DeregisterInstancesFromLoadBalancerExample = `
+
+
+
+
+ i-6ec63d59
+
+
+
+
+ 83c88b9d-12b7-11e3-8b82-87b12EXAMPLE
+
+
+`
+
+// http://docs.aws.amazon.com/ElasticLoadBalancing/latest/APIReference/API_ConfigureHealthCheck.html
+var ConfigureHealthCheckExample = `
+
+
+
+ 30
+ HTTP:80/ping
+ 2
+ 3
+ 2
+
+
+
+ 83c88b9d-12b7-11e3-8b82-87b12EXAMPLE
+
+`
+
+// http://goo.gl/cGNxfj
+var DescribeInstanceHealthExample = `
+
+
+
+
+ N/A
+ i-90d8c2a5
+ InService
+ N/A
+
+
+ N/A
+ i-06ea3e60
+ OutOfService
+ N/A
+
+
+
+
+ 1549581b-12b7-11e3-895e-1334aEXAMPLE
+
+`
diff --git a/Godeps/_workspace/src/github.com/mitchellh/goamz/elb/sign.go b/Godeps/_workspace/src/github.com/mitchellh/goamz/elb/sign.go
new file mode 100644
index 00000000000..06310304dd2
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/mitchellh/goamz/elb/sign.go
@@ -0,0 +1,38 @@
+package elb
+
+import (
+ "crypto/hmac"
+ "crypto/sha256"
+ "encoding/base64"
+ "github.com/mitchellh/goamz/aws"
+ "sort"
+ "strings"
+)
+
+// ----------------------------------------------------------------------------
+// Version 2 signing (http://goo.gl/RSRp5)
+
+var b64 = base64.StdEncoding
+
+func sign(auth aws.Auth, method, path string, params map[string]string, host string) {
+ params["AWSAccessKeyId"] = auth.AccessKey
+ params["SignatureVersion"] = "2"
+ params["SignatureMethod"] = "HmacSHA256"
+ if auth.Token != "" {
+ params["SecurityToken"] = auth.Token
+ }
+
+ var sarray []string
+ for k, v := range params {
+ sarray = append(sarray, aws.Encode(k)+"="+aws.Encode(v))
+ }
+ sort.StringSlice(sarray).Sort()
+ joined := strings.Join(sarray, "&")
+ payload := method + "\n" + host + "\n" + path + "\n" + joined
+ hash := hmac.New(sha256.New, []byte(auth.SecretKey))
+ hash.Write([]byte(payload))
+ signature := make([]byte, b64.EncodedLen(hash.Size()))
+ b64.Encode(signature, hash.Sum(nil))
+
+ params["Signature"] = string(signature)
+}