mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-14 14:23:37 +00:00
Use AWS SDK EC2 metadata client.
This commit is contained in:
parent
df0718caa1
commit
9cd91d111d
@ -20,7 +20,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -34,6 +33,7 @@ import (
|
|||||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
|
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||||
"github.com/aws/aws-sdk-go/service/autoscaling"
|
"github.com/aws/aws-sdk-go/service/autoscaling"
|
||||||
"github.com/aws/aws-sdk-go/service/ec2"
|
"github.com/aws/aws-sdk-go/service/ec2"
|
||||||
"github.com/aws/aws-sdk-go/service/elb"
|
"github.com/aws/aws-sdk-go/service/elb"
|
||||||
@ -61,7 +61,7 @@ type AWSServices interface {
|
|||||||
Compute(region string) (EC2, error)
|
Compute(region string) (EC2, error)
|
||||||
LoadBalancing(region string) (ELB, error)
|
LoadBalancing(region string) (ELB, error)
|
||||||
Autoscaling(region string) (ASG, error)
|
Autoscaling(region string) (ASG, error)
|
||||||
Metadata() AWSMetadata
|
Metadata() (EC2Metadata, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Should we rename this to AWS (EBS & ELB are not technically part of EC2)
|
// TODO: Should we rename this to AWS (EBS & ELB are not technically part of EC2)
|
||||||
@ -129,9 +129,9 @@ type ASG interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Abstraction over the AWS metadata service
|
// Abstraction over the AWS metadata service
|
||||||
type AWSMetadata interface {
|
type EC2Metadata interface {
|
||||||
// Query the EC2 metadata service (used to discover instance-id etc)
|
// Query the EC2 metadata service (used to discover instance-id etc)
|
||||||
GetMetaData(key string) ([]byte, error)
|
GetMetadata(path string) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type VolumeOptions struct {
|
type VolumeOptions struct {
|
||||||
@ -175,6 +175,7 @@ type AWSCloud struct {
|
|||||||
ec2 EC2
|
ec2 EC2
|
||||||
elb ELB
|
elb ELB
|
||||||
asg ASG
|
asg ASG
|
||||||
|
metadata EC2Metadata
|
||||||
cfg *AWSCloudConfig
|
cfg *AWSCloudConfig
|
||||||
availabilityZone string
|
availabilityZone string
|
||||||
region string
|
region string
|
||||||
@ -232,8 +233,9 @@ func (p *awsSDKProvider) Autoscaling(regionName string) (ASG, error) {
|
|||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *awsSDKProvider) Metadata() AWSMetadata {
|
func (p *awsSDKProvider) Metadata() (EC2Metadata, error) {
|
||||||
return &awsSdkMetadata{}
|
client := ec2metadata.New(nil)
|
||||||
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func stringPointerArray(orig []string) []*string {
|
func stringPointerArray(orig []string) []*string {
|
||||||
@ -307,34 +309,16 @@ func (self *awsSdkEC2) DescribeInstances(request *ec2.DescribeInstancesInput) ([
|
|||||||
}
|
}
|
||||||
|
|
||||||
type awsSdkMetadata struct {
|
type awsSdkMetadata struct {
|
||||||
|
metadata *ec2metadata.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
var metadataClient = http.Client{
|
var metadataClient = http.Client{
|
||||||
Timeout: time.Second * 10,
|
Timeout: time.Second * 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements AWSMetadata.GetMetaData
|
// Implements EC2Metadata.GetMetadata
|
||||||
func (self *awsSdkMetadata) GetMetaData(key string) ([]byte, error) {
|
func (self *awsSdkMetadata) GetMetadata(path string) (string, error) {
|
||||||
// TODO Get an implementation of this merged into aws-sdk-go
|
return self.metadata.GetMetadata(path)
|
||||||
url := "http://169.254.169.254/latest/meta-data/" + key
|
|
||||||
|
|
||||||
res, err := metadataClient.Get(url)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
if res.StatusCode != 200 {
|
|
||||||
err = fmt.Errorf("Code %d returned for url %s", res.StatusCode, url)
|
|
||||||
return nil, fmt.Errorf("Error querying AWS metadata for key %s: %v", key, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Error querying AWS metadata for key %s: %v", key, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return []byte(body), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements EC2.DescribeSecurityGroups
|
// Implements EC2.DescribeSecurityGroups
|
||||||
@ -466,7 +450,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// readAWSCloudConfig reads an instance of AWSCloudConfig from config reader.
|
// readAWSCloudConfig reads an instance of AWSCloudConfig from config reader.
|
||||||
func readAWSCloudConfig(config io.Reader, metadata AWSMetadata) (*AWSCloudConfig, error) {
|
func readAWSCloudConfig(config io.Reader, metadata EC2Metadata) (*AWSCloudConfig, error) {
|
||||||
var cfg AWSCloudConfig
|
var cfg AWSCloudConfig
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
@ -493,15 +477,8 @@ func readAWSCloudConfig(config io.Reader, metadata AWSMetadata) (*AWSCloudConfig
|
|||||||
return &cfg, nil
|
return &cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAvailabilityZone(metadata AWSMetadata) (string, error) {
|
func getAvailabilityZone(metadata EC2Metadata) (string, error) {
|
||||||
availabilityZoneBytes, err := metadata.GetMetaData("placement/availability-zone")
|
return metadata.GetMetadata("placement/availability-zone")
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if availabilityZoneBytes == nil || len(availabilityZoneBytes) == 0 {
|
|
||||||
return "", fmt.Errorf("Unable to determine availability-zone from instance metadata")
|
|
||||||
}
|
|
||||||
return string(availabilityZoneBytes), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func isRegionValid(region string) bool {
|
func isRegionValid(region string) bool {
|
||||||
@ -527,7 +504,11 @@ func isRegionValid(region string) bool {
|
|||||||
// newAWSCloud creates a new instance of AWSCloud.
|
// newAWSCloud creates a new instance of AWSCloud.
|
||||||
// AWSProvider and instanceId are primarily for tests
|
// AWSProvider and instanceId are primarily for tests
|
||||||
func newAWSCloud(config io.Reader, awsServices AWSServices) (*AWSCloud, error) {
|
func newAWSCloud(config io.Reader, awsServices AWSServices) (*AWSCloud, error) {
|
||||||
metadata := awsServices.Metadata()
|
metadata, err := awsServices.Metadata()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error creating AWS metadata client: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
cfg, err := readAWSCloudConfig(config, metadata)
|
cfg, err := readAWSCloudConfig(config, metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to read AWS cloud provider config file: %v", err)
|
return nil, fmt.Errorf("unable to read AWS cloud provider config file: %v", err)
|
||||||
@ -564,6 +545,7 @@ func newAWSCloud(config io.Reader, awsServices AWSServices) (*AWSCloud, error) {
|
|||||||
ec2: ec2,
|
ec2: ec2,
|
||||||
elb: elb,
|
elb: elb,
|
||||||
asg: asg,
|
asg: asg,
|
||||||
|
metadata: metadata,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
region: regionName,
|
region: regionName,
|
||||||
availabilityZone: zone,
|
availabilityZone: zone,
|
||||||
@ -1059,17 +1041,16 @@ func (s *AWSCloud) getSelfAWSInstance() (*awsInstance, error) {
|
|||||||
|
|
||||||
i := s.selfAWSInstance
|
i := s.selfAWSInstance
|
||||||
if i == nil {
|
if i == nil {
|
||||||
metadata := s.awsServices.Metadata()
|
instanceId, err := s.metadata.GetMetadata("instance-id")
|
||||||
instanceIdBytes, err := metadata.GetMetaData("instance-id")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error fetching instance-id from ec2 metadata service: %v", err)
|
return nil, fmt.Errorf("error fetching instance-id from ec2 metadata service: %v", err)
|
||||||
}
|
}
|
||||||
privateDnsNameBytes, err := metadata.GetMetaData("local-hostname")
|
privateDnsName, err := s.metadata.GetMetadata("local-hostname")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error fetching local-hostname from ec2 metadata service: %v", err)
|
return nil, fmt.Errorf("error fetching local-hostname from ec2 metadata service: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
i = newAWSInstance(s.ec2, string(instanceIdBytes), string(privateDnsNameBytes))
|
i = newAWSInstance(s.ec2, instanceId, privateDnsName)
|
||||||
s.selfAWSInstance = i
|
s.selfAWSInstance = i
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1254,27 +1235,24 @@ func (s *AWSCloud) describeLoadBalancer(name string) (*elb.LoadBalancerDescripti
|
|||||||
|
|
||||||
// Retrieves instance's vpc id from metadata
|
// Retrieves instance's vpc id from metadata
|
||||||
func (self *AWSCloud) findVPCID() (string, error) {
|
func (self *AWSCloud) findVPCID() (string, error) {
|
||||||
|
macs, err := self.metadata.GetMetadata("network/interfaces/macs/")
|
||||||
metadata := self.awsServices.Metadata()
|
|
||||||
macsBytes, err := metadata.GetMetaData("network/interfaces/macs/")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Could not list interfaces of the instance", err)
|
return "", fmt.Errorf("Could not list interfaces of the instance", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// loop over interfaces, first vpc id returned wins
|
// loop over interfaces, first vpc id returned wins
|
||||||
for _, macPath := range strings.Split(string(macsBytes), "\n") {
|
for _, macPath := range strings.Split(macs, "\n") {
|
||||||
|
|
||||||
if len(macPath) == 0 {
|
if len(macPath) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
url := fmt.Sprintf("network/interfaces/macs/%svpc-id", macPath)
|
url := fmt.Sprintf("network/interfaces/macs/%svpc-id", macPath)
|
||||||
vpcIDBytes, err := metadata.GetMetaData(url)
|
vpcID, err := self.metadata.GetMetadata(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return string(vpcIDBytes), nil
|
return vpcID, nil
|
||||||
}
|
}
|
||||||
return "", fmt.Errorf("Could not find VPC id in instance metadata")
|
return "", fmt.Errorf("Could not find VPC ID in instance metadata")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the VPC which self is attached to.
|
// Find the VPC which self is attached to.
|
||||||
|
@ -83,9 +83,9 @@ func TestReadAWSCloudConfig(t *testing.T) {
|
|||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Logf("Running test case %s", test.name)
|
t.Logf("Running test case %s", test.name)
|
||||||
var metadata AWSMetadata
|
var metadata EC2Metadata
|
||||||
if test.aws != nil {
|
if test.aws != nil {
|
||||||
metadata = test.aws.Metadata()
|
metadata, _ = test.aws.Metadata()
|
||||||
}
|
}
|
||||||
cfg, err := readAWSCloudConfig(test.reader, metadata)
|
cfg, err := readAWSCloudConfig(test.reader, metadata)
|
||||||
if test.expectError {
|
if test.expectError {
|
||||||
@ -166,8 +166,8 @@ func (s *FakeAWSServices) Autoscaling(region string) (ASG, error) {
|
|||||||
return s.asg, nil
|
return s.asg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FakeAWSServices) Metadata() AWSMetadata {
|
func (s *FakeAWSServices) Metadata() (EC2Metadata, error) {
|
||||||
return s.metadata
|
return s.metadata, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFilterTags(t *testing.T) {
|
func TestFilterTags(t *testing.T) {
|
||||||
@ -313,31 +313,31 @@ type FakeMetadata struct {
|
|||||||
aws *FakeAWSServices
|
aws *FakeAWSServices
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *FakeMetadata) GetMetaData(key string) ([]byte, error) {
|
func (self *FakeMetadata) GetMetadata(key string) (string, error) {
|
||||||
networkInterfacesPrefix := "network/interfaces/macs/"
|
networkInterfacesPrefix := "network/interfaces/macs/"
|
||||||
if key == "placement/availability-zone" {
|
if key == "placement/availability-zone" {
|
||||||
return []byte(self.aws.availabilityZone), nil
|
return self.aws.availabilityZone, nil
|
||||||
} else if key == "instance-id" {
|
} else if key == "instance-id" {
|
||||||
return []byte(self.aws.instanceId), nil
|
return self.aws.instanceId, nil
|
||||||
} else if key == "local-hostname" {
|
} else if key == "local-hostname" {
|
||||||
return []byte(self.aws.privateDnsName), nil
|
return self.aws.privateDnsName, nil
|
||||||
} else if strings.HasPrefix(key, networkInterfacesPrefix) {
|
} else if strings.HasPrefix(key, networkInterfacesPrefix) {
|
||||||
if key == networkInterfacesPrefix {
|
if key == networkInterfacesPrefix {
|
||||||
return []byte(strings.Join(self.aws.networkInterfacesMacs, "/\n") + "/\n"), nil
|
return strings.Join(self.aws.networkInterfacesMacs, "/\n") + "/\n", nil
|
||||||
} else {
|
} else {
|
||||||
keySplit := strings.Split(key, "/")
|
keySplit := strings.Split(key, "/")
|
||||||
macParam := keySplit[3]
|
macParam := keySplit[3]
|
||||||
if len(keySplit) == 5 && keySplit[4] == "vpc-id" {
|
if len(keySplit) == 5 && keySplit[4] == "vpc-id" {
|
||||||
for i, macElem := range self.aws.networkInterfacesMacs {
|
for i, macElem := range self.aws.networkInterfacesMacs {
|
||||||
if macParam == macElem {
|
if macParam == macElem {
|
||||||
return []byte(self.aws.networkInterfacesVpcIDs[i]), nil
|
return self.aws.networkInterfacesVpcIDs[i], nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, nil
|
return "", nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil, nil
|
return "", nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user