diff options
Diffstat (limited to 'vendor/github.com/goamz/goamz/elb/elb.go')
-rw-r--r-- | vendor/github.com/goamz/goamz/elb/elb.go | 435 |
1 files changed, 435 insertions, 0 deletions
diff --git a/vendor/github.com/goamz/goamz/elb/elb.go b/vendor/github.com/goamz/goamz/elb/elb.go new file mode 100644 index 000000000..0127435a7 --- /dev/null +++ b/vendor/github.com/goamz/goamz/elb/elb.go @@ -0,0 +1,435 @@ +// This package provides types and functions to interact Elastic Load Balancing service +package elb + +import ( + "encoding/xml" + "fmt" + "net/http" + "net/url" + "sort" + "strconv" + "strings" + "time" + + "github.com/goamz/goamz/aws" +) + +type ELB struct { + aws.Auth + aws.Region +} + +func New(auth aws.Auth, region aws.Region) *ELB { + return &ELB{auth, region} +} + +// The CreateLoadBalancer type encapsulates options for the respective request in AWS. +// The creation of a Load Balancer may differ inside EC2 and VPC. +// +// See http://goo.gl/4QFKi for more details. +type CreateLoadBalancer struct { + Name string + AvailabilityZones []string + Listeners []Listener + Scheme string + SecurityGroups []string + Subnets []string +} + +// Listener to configure in Load Balancer. +// +// See http://goo.gl/NJQCj for more details. +type Listener struct { + InstancePort int + InstanceProtocol string + LoadBalancerPort int + Protocol string + SSLCertificateId string +} + +// Response to a CreateLoadBalance request. +// +// See http://goo.gl/4QFKi for more details. +type CreateLoadBalancerResp struct { + DNSName string `xml:"CreateLoadBalancerResult>DNSName"` +} + +type SimpleResp struct { + RequestId string `xml:"ResponseMetadata>RequestId"` +} + +// Creates a Load Balancer in Amazon. +// +// See http://goo.gl/4QFKi for more details. +func (elb *ELB) CreateLoadBalancer(options *CreateLoadBalancer) (resp *CreateLoadBalancerResp, err error) { + params := makeCreateParams(options) + resp = new(CreateLoadBalancerResp) + if err := elb.query(params, resp); err != nil { + return nil, err + } + return +} + +// Deletes a Load Balancer. +// +// See http://goo.gl/sDmPp for more details. +func (elb *ELB) DeleteLoadBalancer(name string) (resp *SimpleResp, err error) { + params := map[string]string{ + "Action": "DeleteLoadBalancer", + "LoadBalancerName": name, + } + resp = new(SimpleResp) + if err := elb.query(params, resp); err != nil { + return nil, err + } + return resp, nil +} + +type RegisterInstancesResp struct { + InstanceIds []string `xml:"RegisterInstancesWithLoadBalancerResult>Instances>member>InstanceId"` +} + +// Register N instances with a given Load Balancer. +// +// See http://goo.gl/x9hru for more details. +func (elb *ELB) RegisterInstancesWithLoadBalancer(instanceIds []string, lbName string) (resp *RegisterInstancesResp, err error) { + // TODO: change params order and use ..., e.g (lbName string, instanceIds ...string) + params := map[string]string{ + "Action": "RegisterInstancesWithLoadBalancer", + "LoadBalancerName": lbName, + } + for i, instanceId := range instanceIds { + key := fmt.Sprintf("Instances.member.%d.InstanceId", i+1) + params[key] = instanceId + } + resp = new(RegisterInstancesResp) + if err := elb.query(params, resp); err != nil { + return nil, err + } + return resp, nil +} + +// Deregister N instances from a given Load Balancer. +// +// See http://goo.gl/Hgo4U for more details. +func (elb *ELB) DeregisterInstancesFromLoadBalancer(instanceIds []string, lbName string) (resp *SimpleResp, err error) { + // TODO: change params order and use ..., e.g (lbName string, instanceIds ...string) + params := map[string]string{ + "Action": "DeregisterInstancesFromLoadBalancer", + "LoadBalancerName": lbName, + } + for i, instanceId := range instanceIds { + key := fmt.Sprintf("Instances.member.%d.InstanceId", i+1) + params[key] = instanceId + } + resp = new(SimpleResp) + if err := elb.query(params, resp); err != nil { + return nil, err + } + return resp, nil +} + +type DescribeLoadBalancerResp struct { + LoadBalancerDescriptions []LoadBalancerDescription `xml:"DescribeLoadBalancersResult>LoadBalancerDescriptions>member"` +} + +type LoadBalancerDescription struct { + AvailabilityZones []string `xml:"AvailabilityZones>member"` + BackendServerDescriptions []BackendServerDescriptions `xml:"BackendServerDescriptions>member"` + CanonicalHostedZoneName string `xml:"CanonicalHostedZoneName"` + CanonicalHostedZoneNameId string `xml:"CanonicalHostedZoneNameID"` + CreatedTime time.Time `xml:"CreatedTime"` + DNSName string `xml:"DNSName"` + HealthCheck HealthCheck `xml:"HealthCheck"` + Instances []Instance `xml:"Instances>member"` + ListenerDescriptions []ListenerDescription `xml:"ListenerDescriptions>member"` + LoadBalancerName string `xml:"LoadBalancerName"` + Policies Policies `xml:"Policies"` + Scheme string `xml:"Scheme"` + SecurityGroups []string `xml:"SecurityGroups>member"` //vpc only + SourceSecurityGroup SourceSecurityGroup `xml:"SourceSecurityGroup"` + Subnets []string `xml:"Subnets>member"` + VPCId string `xml:"VPCId"` +} + +// Describe Load Balancers. +// It can be used to describe all Load Balancers or specific ones. +// +// See http://goo.gl/wofJA for more details. +func (elb *ELB) DescribeLoadBalancers(names ...string) (*DescribeLoadBalancerResp, error) { + params := map[string]string{"Action": "DescribeLoadBalancers"} + for i, name := range names { + index := fmt.Sprintf("LoadBalancerNames.member.%d", i+1) + params[index] = name + } + resp := new(DescribeLoadBalancerResp) + if err := elb.query(params, resp); err != nil { + return nil, err + } + return resp, nil +} + +type BackendServerDescriptions struct { + InstancePort int `xml:"InstancePort"` + PolicyNames []string `xml:"PolicyNames>member"` +} + +type HealthCheck struct { + HealthyThreshold int `xml:"HealthyThreshold"` + Interval int `xml:"Interval"` + Target string `xml:"Target"` + Timeout int `xml:"Timeout"` + UnhealthyThreshold int `xml:"UnhealthyThreshold"` +} + +type Instance struct { + InstanceId string `xml:"InstanceId"` +} + +type ListenerDescription struct { + Listener Listener `xml:"Listener"` + PolicyNames []string `xml:"PolicyNames>member"` +} + +type Policies struct { + AppCookieStickinessPolicies []AppCookieStickinessPolicies `xml:"AppCookieStickinessPolicies>member"` + LBCookieStickinessPolicies []LBCookieStickinessPolicies `xml:"LBCookieStickinessPolicies>member"` + OtherPolicies []string `xml:"OtherPolicies>member"` +} + +// see http://goo.gl/clXGV for more information. +type AppCookieStickinessPolicies struct { + CookieName string `xml:"CookieName"` + PolicyName string `xml:"PolicyName"` +} + +type LBCookieStickinessPolicies struct { + CookieExpirationPeriod int `xml:"CookieExpirationPeriod"` + PolicyName string `xml:"PolicyName"` +} + +type SourceSecurityGroup struct { + GroupName string `xml:"GroupName"` + OwnerAlias string `xml:"OwnerAlias"` +} + +// Represents a XML response for DescribeInstanceHealth action +// +// See http://goo.gl/ovIB1 for more information. +type DescribeInstanceHealthResp struct { + InstanceStates []InstanceState `xml:"DescribeInstanceHealthResult>InstanceStates>member"` +} + +// See http://goo.gl/dzWfP for more information. +type InstanceState struct { + Description string `xml:"Description"` + InstanceId string `xml:"InstanceId"` + ReasonCode string `xml:"ReasonCode"` + State string `xml:"State"` +} + +// Describe instance health. +// +// See http://goo.gl/ovIB1 for more information. +func (elb *ELB) DescribeInstanceHealth(lbName string, instanceIds ...string) (*DescribeInstanceHealthResp, error) { + params := map[string]string{ + "Action": "DescribeInstanceHealth", + "LoadBalancerName": lbName, + } + for i, iId := range instanceIds { + key := fmt.Sprintf("Instances.member.%d.InstanceId", i+1) + params[key] = iId + } + resp := new(DescribeInstanceHealthResp) + if err := elb.query(params, resp); err != nil { + return nil, err + } + return resp, nil +} + +type HealthCheckResp struct { + HealthCheck *HealthCheck `xml:"ConfigureHealthCheckResult>HealthCheck"` +} + +// Configure health check for a LB +// +// See http://goo.gl/2HE6a for more information +func (elb *ELB) ConfigureHealthCheck(lbName string, healthCheck *HealthCheck) (*HealthCheckResp, error) { + params := map[string]string{ + "Action": "ConfigureHealthCheck", + "LoadBalancerName": lbName, + "HealthCheck.HealthyThreshold": strconv.Itoa(healthCheck.HealthyThreshold), + "HealthCheck.Interval": strconv.Itoa(healthCheck.Interval), + "HealthCheck.Target": healthCheck.Target, + "HealthCheck.Timeout": strconv.Itoa(healthCheck.Timeout), + "HealthCheck.UnhealthyThreshold": strconv.Itoa(healthCheck.UnhealthyThreshold), + } + resp := new(HealthCheckResp) + if err := elb.query(params, resp); err != nil { + return nil, err + } + return resp, nil +} + +// Add tags to the named ELB +// +// Note that AWS only accepts one ELB name at a time (even though it is sent as a list) +// +// See http://goo.gl/6JW4Wf for the rest of the details +func (elb *ELB) AddTags(elbName string, tags map[string]string) (*SimpleResp, error) { + var sortedKeys []string + params := make(map[string]string) + response := &SimpleResp{} + + for tagKey := range tags { + sortedKeys = append(sortedKeys, tagKey) + } + + sort.Strings(sortedKeys) + + for _, key := range sortedKeys { + number := len(tags) + params[fmt.Sprintf("Tags.member.%d.Key", number)] = key + params[fmt.Sprintf("Tags.member.%d.Value", number)] = tags[key] + delete(tags, key) + } + + params["Action"] = "AddTags" + params["LoadBalancerNames.member.1"] = elbName + + if err := elb.query(params, response); err != nil { + return nil, err + } + + return response, nil +} + +// Remove tags from the named ELB +// +// Note that AWS only accepts one ELB name at a time (even though it is sent as a list) +// +// see http://goo.gl/ochFqo for more details + +func (elb *ELB) RemoveTags(elbName string, tagKeys []string) (*SimpleResp, error) { + response := &SimpleResp{} + params := make(map[string]string) + + params["Action"] = "RemoveTags" + params["LoadBalancerNames.member.1"] = elbName + + for i, tagKey := range tagKeys { + params[fmt.Sprintf("Tags.member.%d.Key", i+1)] = tagKey + } + + if err := elb.query(params, response); err != nil { + return nil, err + } + + return response, nil +} + +func (elb *ELB) query(params map[string]string, resp interface{}) error { + params["Version"] = "2012-06-01" + params["Timestamp"] = time.Now().In(time.UTC).Format(time.RFC3339) + data := strings.NewReader(multimap(params).Encode()) + hreq, err := http.NewRequest("GET", elb.Region.ELBEndpoint+"/", data) + if err != nil { + return err + } + + hreq.URL.RawQuery = multimap(params).Encode() + token := elb.Auth.Token() + if token != "" { + hreq.Header.Set("X-Amz-Security-Token", token) + } + + signer := aws.NewV4Signer(elb.Auth, "elasticloadbalancing", elb.Region) + signer.Sign(hreq) + + r, err := http.DefaultClient.Do(hreq) + + if err != nil { + return err + } + defer r.Body.Close() + if r.StatusCode != 200 { + return buildError(r) + } + return xml.NewDecoder(r.Body).Decode(resp) +} + +// Error encapsulates an error returned by ELB. +type Error struct { + // HTTP status code + StatusCode int + // AWS error code + Code string + // The human-oriented error message + Message string +} + +func (err *Error) Error() string { + if err.Code == "" { + return err.Message + } + + return fmt.Sprintf("%s (%s)", err.Message, err.Code) +} + +type xmlErrors struct { + Errors []Error `xml:"Error"` +} + +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 makeCreateParams(createLB *CreateLoadBalancer) map[string]string { + params := make(map[string]string) + params["LoadBalancerName"] = createLB.Name + params["Action"] = "CreateLoadBalancer" + if createLB.Scheme != "" { + params["Scheme"] = createLB.Scheme + } + for i, s := range createLB.SecurityGroups { + key := fmt.Sprintf("SecurityGroups.member.%d", i+1) + params[key] = s + } + for i, s := range createLB.Subnets { + key := fmt.Sprintf("Subnets.member.%d", i+1) + params[key] = s + } + for i, l := range createLB.Listeners { + key := "Listeners.member.%d.%s" + index := i + 1 + params[fmt.Sprintf(key, index, "InstancePort")] = strconv.Itoa(l.InstancePort) + params[fmt.Sprintf(key, index, "InstanceProtocol")] = l.InstanceProtocol + params[fmt.Sprintf(key, index, "Protocol")] = l.Protocol + params[fmt.Sprintf(key, index, "LoadBalancerPort")] = strconv.Itoa(l.LoadBalancerPort) + } + for i, az := range createLB.AvailabilityZones { + key := fmt.Sprintf("AvailabilityZones.member.%d", i+1) + params[key] = az + } + return params +} |