mirror of https://github.com/kubernetes/kops.git
242 lines
6.1 KiB
Go
242 lines
6.1 KiB
Go
package awsup
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
"github.com/aws/aws-sdk-go/aws/session"
|
|
"github.com/aws/aws-sdk-go/service/autoscaling"
|
|
"github.com/aws/aws-sdk-go/service/ec2"
|
|
"github.com/aws/aws-sdk-go/service/elb"
|
|
"github.com/aws/aws-sdk-go/service/iam"
|
|
"github.com/golang/glog"
|
|
"k8s.io/kube-deploy/upup/pkg/fi"
|
|
"strings"
|
|
)
|
|
|
|
type AWSCloud struct {
|
|
EC2 *ec2.EC2
|
|
IAM *iam.IAM
|
|
ELB *elb.ELB
|
|
Autoscaling *autoscaling.AutoScaling
|
|
|
|
Region string
|
|
|
|
tags map[string]string
|
|
}
|
|
|
|
var _ fi.Cloud = &AWSCloud{}
|
|
|
|
func (c *AWSCloud) ProviderID() fi.CloudProviderID {
|
|
return fi.CloudProviderAWS
|
|
}
|
|
|
|
func NewAWSCloud(region string, tags map[string]string) (*AWSCloud, error) {
|
|
c := &AWSCloud{Region: region}
|
|
|
|
config := aws.NewConfig().WithRegion(region)
|
|
c.EC2 = ec2.New(session.New(), config)
|
|
c.IAM = iam.New(session.New(), config)
|
|
c.ELB = elb.New(session.New(), config)
|
|
c.Autoscaling = autoscaling.New(session.New(), config)
|
|
|
|
c.tags = tags
|
|
return c, nil
|
|
}
|
|
|
|
func NewEC2Filter(name string, values ...string) *ec2.Filter {
|
|
awsValues := []*string{}
|
|
for _, value := range values {
|
|
awsValues = append(awsValues, aws.String(value))
|
|
}
|
|
filter := &ec2.Filter{
|
|
Name: aws.String(name),
|
|
Values: awsValues,
|
|
}
|
|
return filter
|
|
}
|
|
|
|
func (c *AWSCloud) Tags() map[string]string {
|
|
// Defensive copy
|
|
tags := make(map[string]string)
|
|
for k, v := range c.tags {
|
|
tags[k] = v
|
|
}
|
|
return tags
|
|
}
|
|
|
|
func (c *AWSCloud) GetTags(resourceId string) (map[string]string, error) {
|
|
tags := map[string]string{}
|
|
|
|
request := &ec2.DescribeTagsInput{
|
|
Filters: []*ec2.Filter{
|
|
NewEC2Filter("resource-id", resourceId),
|
|
},
|
|
}
|
|
|
|
response, err := c.EC2.DescribeTags(request)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error listing tags on %v: %v", resourceId, err)
|
|
}
|
|
|
|
for _, tag := range response.Tags {
|
|
if tag == nil {
|
|
glog.Warning("unexpected nil tag")
|
|
continue
|
|
}
|
|
tags[aws.StringValue(tag.Key)] = aws.StringValue(tag.Value)
|
|
}
|
|
|
|
return tags, nil
|
|
}
|
|
|
|
func (c *AWSCloud) CreateTags(resourceId string, tags map[string]string) error {
|
|
if len(tags) == 0 {
|
|
return nil
|
|
}
|
|
|
|
ec2Tags := []*ec2.Tag{}
|
|
for k, v := range tags {
|
|
ec2Tags = append(ec2Tags, &ec2.Tag{Key: aws.String(k), Value: aws.String(v)})
|
|
}
|
|
request := &ec2.CreateTagsInput{
|
|
Tags: ec2Tags,
|
|
Resources: []*string{&resourceId},
|
|
}
|
|
|
|
_, err := c.EC2.CreateTags(request)
|
|
if err != nil {
|
|
return fmt.Errorf("error creating tags on %v: %v", resourceId, err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *AWSCloud) BuildTags(name *string) map[string]string {
|
|
tags := make(map[string]string)
|
|
if name != nil {
|
|
tags["Name"] = *name
|
|
} else {
|
|
glog.Warningf("Name not set when filtering by name")
|
|
}
|
|
for k, v := range c.tags {
|
|
tags[k] = v
|
|
}
|
|
return tags
|
|
}
|
|
|
|
func (c *AWSCloud) BuildFilters(name *string) []*ec2.Filter {
|
|
filters := []*ec2.Filter{}
|
|
|
|
merged := make(map[string]string)
|
|
if name != nil {
|
|
merged["Name"] = *name
|
|
} else {
|
|
glog.Warningf("Name not set when filtering by name")
|
|
}
|
|
for k, v := range c.tags {
|
|
merged[k] = v
|
|
}
|
|
|
|
for k, v := range merged {
|
|
filter := NewEC2Filter("tag:"+k, v)
|
|
filters = append(filters, filter)
|
|
}
|
|
return filters
|
|
}
|
|
|
|
// DescribeInstance is a helper that queries for the specified instance by id
|
|
func (t *AWSCloud) DescribeInstance(instanceID string) (*ec2.Instance, error) {
|
|
glog.V(2).Infof("Calling DescribeInstances for instance %q", instanceID)
|
|
request := &ec2.DescribeInstancesInput{
|
|
InstanceIds: []*string{&instanceID},
|
|
}
|
|
|
|
response, err := t.EC2.DescribeInstances(request)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error listing Instances: %v", err)
|
|
}
|
|
if response == nil || len(response.Reservations) == 0 {
|
|
return nil, nil
|
|
}
|
|
if len(response.Reservations) != 1 {
|
|
glog.Fatalf("found multiple Reservations for instance id")
|
|
}
|
|
|
|
reservation := response.Reservations[0]
|
|
if len(reservation.Instances) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
if len(reservation.Instances) != 1 {
|
|
return nil, fmt.Errorf("found multiple Instances for instance id")
|
|
}
|
|
|
|
instance := reservation.Instances[0]
|
|
return instance, nil
|
|
}
|
|
|
|
// DescribeVPC is a helper that queries for the specified vpc by id
|
|
func (t *AWSCloud) DescribeVPC(vpcID string) (*ec2.Vpc, error) {
|
|
glog.V(2).Infof("Calilng DescribeVPC for VPC %q", vpcID)
|
|
request := &ec2.DescribeVpcsInput{
|
|
VpcIds: []*string{&vpcID},
|
|
}
|
|
|
|
response, err := t.EC2.DescribeVpcs(request)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error listing VPCs: %v", err)
|
|
}
|
|
if response == nil || len(response.Vpcs) == 0 {
|
|
return nil, nil
|
|
}
|
|
if len(response.Vpcs) != 1 {
|
|
return nil, fmt.Errorf("found multiple VPCs for instance id")
|
|
}
|
|
|
|
vpc := response.Vpcs[0]
|
|
return vpc, nil
|
|
}
|
|
|
|
// ResolveImage finds an AMI image based on the given name.
|
|
// The name can be one of:
|
|
// `ami-...` in which case it is presumed to be an id
|
|
// owner/name in which case we find the image with the specified name, owned by owner
|
|
// name in which case we find the image with the specified name, with the current owner
|
|
func (c *AWSCloud) ResolveImage(name string) (*ec2.Image, error) {
|
|
// TODO: Cache this result during a single execution (we get called multiple times)
|
|
glog.V(2).Infof("Calilng DescribeImages to resolve name %q", name)
|
|
request := &ec2.DescribeImagesInput{}
|
|
|
|
if strings.HasPrefix(name, "ami-") {
|
|
// ami-xxxxxxxx
|
|
request.ImageIds = []*string{&name}
|
|
} else {
|
|
// Either <imagename> or <owner>/<imagename>
|
|
tokens := strings.Split(name, "/")
|
|
if len(tokens) == 1 {
|
|
// self is a well-known value in the DescribeImages call
|
|
request.Owners = aws.StringSlice([]string{"self"})
|
|
request.Filters = append(request.Filters, NewEC2Filter("name", name))
|
|
} else if len(tokens) == 2 {
|
|
request.Owners = []*string{&tokens[0]}
|
|
request.Filters = append(request.Filters, NewEC2Filter("name", tokens[1]))
|
|
} else {
|
|
return nil, fmt.Errorf("image name specification not recognized: %q", name)
|
|
}
|
|
}
|
|
|
|
response, err := c.EC2.DescribeImages(request)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error listing images: %v", err)
|
|
}
|
|
if response == nil || len(response.Images) == 0 {
|
|
return nil, fmt.Errorf("could not find Image for %q", name)
|
|
}
|
|
if len(response.Images) != 1 {
|
|
return nil, fmt.Errorf("found multiple Images for %q", name)
|
|
}
|
|
|
|
image := response.Images[0]
|
|
return image, nil
|
|
}
|