From 1bfba8a5902fb14d1727e6e042d521b55f37ee39 Mon Sep 17 00:00:00 2001 From: Christian Simon Date: Wed, 2 Sep 2015 16:28:55 +0100 Subject: [PATCH] Enhanced detection of VPC for cloudprovider AWS * use metadata of instance rather than hardcoded VPC name * test coverage for retrieval of network metadata --- pkg/cloudprovider/providers/aws/aws.go | 35 ++++++++++++++-- pkg/cloudprovider/providers/aws/aws_test.go | 45 +++++++++++++++++++-- 2 files changed, 73 insertions(+), 7 deletions(-) diff --git a/pkg/cloudprovider/providers/aws/aws.go b/pkg/cloudprovider/providers/aws/aws.go index d216232557f..6234d1ea6ef 100644 --- a/pkg/cloudprovider/providers/aws/aws.go +++ b/pkg/cloudprovider/providers/aws/aws.go @@ -1281,12 +1281,41 @@ func (self *AWSCloud) TCPLoadBalancerExists(name, region string) (bool, error) { return false, nil } +// Retrieves instance's vpc id from metadata +func (self *AWSCloud) findVPCID() (string, error) { + + metadata := self.awsServices.Metadata() + macsBytes, err := metadata.GetMetaData("network/interfaces/macs/") + if err != nil { + return "", fmt.Errorf("Could not list interfaces of the instance", err) + } + + // loop over interfaces, first vpc id returned wins + for _, macPath := range strings.Split(string(macsBytes), "\n") { + + if len(macPath) == 0 { + continue + } + url := fmt.Sprintf("network/interfaces/macs/%svpc-id", macPath) + vpcIDBytes, err := metadata.GetMetaData(url) + if err != nil { + continue + } + return string(vpcIDBytes), nil + } + return "", fmt.Errorf("Could not find VPC id in instance metadata") +} + // Find the kubernetes VPC func (self *AWSCloud) findVPC() (*ec2.VPC, error) { request := &ec2.DescribeVPCsInput{} - name := "kubernetes-vpc" - filters := []*ec2.Filter{newEc2Filter("tag:Name", name)} + // find by vpcID from metadata + vpcID, err := self.findVPCID() + if err != nil { + return nil, err + } + filters := []*ec2.Filter{newEc2Filter("vpc-id", vpcID)} request.Filters = self.addFilters(filters) vpcs, err := self.ec2.DescribeVPCs(request) @@ -1301,7 +1330,7 @@ func (self *AWSCloud) findVPC() (*ec2.VPC, error) { if len(vpcs) == 1 { return vpcs[0], nil } - return nil, fmt.Errorf("Found multiple matching VPCs for name: %s", name) + return nil, fmt.Errorf("Found multiple matching VPCs for vpcID = %s", vpcID) } // Retrieves the specified security group from the AWS API, or returns nil if not found diff --git a/pkg/cloudprovider/providers/aws/aws_test.go b/pkg/cloudprovider/providers/aws/aws_test.go index 29bbd8a2e07..07171a11827 100644 --- a/pkg/cloudprovider/providers/aws/aws_test.go +++ b/pkg/cloudprovider/providers/aws/aws_test.go @@ -104,10 +104,12 @@ func TestReadAWSCloudConfig(t *testing.T) { } type FakeAWSServices struct { - availabilityZone string - instances []*ec2.Instance - instanceId string - privateDnsName string + availabilityZone string + instances []*ec2.Instance + instanceId string + privateDnsName string + networkInterfacesMacs []string + networkInterfacesVpcIDs []string ec2 *FakeEC2 elb *FakeELB @@ -123,6 +125,9 @@ func NewFakeAWSServices() *FakeAWSServices { s.asg = &FakeASG{aws: s} s.metadata = &FakeMetadata{aws: s} + s.networkInterfacesMacs = []string{"aa:bb:cc:dd:ee:00", "aa:bb:cc:dd:ee:01"} + s.networkInterfacesVpcIDs = []string{"vpc-mac0", "vpc-mac1"} + s.instanceId = "i-self" s.privateDnsName = "ip-172-20-0-100.ec2.internal" var selfInstance ec2.Instance @@ -308,12 +313,28 @@ type FakeMetadata struct { } func (self *FakeMetadata) GetMetaData(key string) ([]byte, error) { + networkInterfacesPrefix := "network/interfaces/macs/" if key == "placement/availability-zone" { return []byte(self.aws.availabilityZone), nil } else if key == "instance-id" { return []byte(self.aws.instanceId), nil } else if key == "local-hostname" { return []byte(self.aws.privateDnsName), nil + } else if strings.HasPrefix(key, networkInterfacesPrefix) { + if key == networkInterfacesPrefix { + return []byte(strings.Join(self.aws.networkInterfacesMacs, "/\n") + "/\n"), nil + } else { + keySplit := strings.Split(key, "/") + macParam := keySplit[3] + if len(keySplit) == 5 && keySplit[4] == "vpc-id" { + for i, macElem := range self.aws.networkInterfacesMacs { + if macParam == macElem { + return []byte(self.aws.networkInterfacesVpcIDs[i]), nil + } + } + } + return nil, nil + } } else { return nil, nil } @@ -627,3 +648,19 @@ func TestGetRegion(t *testing.T) { t.Errorf("Unexpected FailureDomain: %s", zone.FailureDomain) } } + +func TestFindVPCID(t *testing.T) { + awsServices := NewFakeAWSServices() + c, err := newAWSCloud(strings.NewReader("[global]"), awsServices) + if err != nil { + t.Errorf("Error building aws cloud: %v", err) + return + } + vpcID, err := c.findVPCID() + if err != nil { + t.Errorf("Unexpected error:", err) + } + if vpcID != "vpc-mac0" { + t.Errorf("Unexpected vpcID: %s", vpcID) + } +}