diff --git a/nodeup/pkg/model/BUILD.bazel b/nodeup/pkg/model/BUILD.bazel index 70bee9fff214c..11c548afbca3e 100644 --- a/nodeup/pkg/model/BUILD.bazel +++ b/nodeup/pkg/model/BUILD.bazel @@ -58,8 +58,10 @@ go_library( "//util/pkg/exec:go_default_library", "//util/pkg/reflectutils:go_default_library", "//util/pkg/vfs:go_default_library", + "//vendor/github.com/aws/aws-sdk-go/aws:go_default_library", "//vendor/github.com/aws/aws-sdk-go/aws/ec2metadata:go_default_library", "//vendor/github.com/aws/aws-sdk-go/aws/session:go_default_library", + "//vendor/github.com/aws/aws-sdk-go/service/ec2:go_default_library", "//vendor/github.com/blang/semver:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library", diff --git a/nodeup/pkg/model/context.go b/nodeup/pkg/model/context.go index df400348dbc74..e7de559c68f62 100644 --- a/nodeup/pkg/model/context.go +++ b/nodeup/pkg/model/context.go @@ -33,6 +33,10 @@ import ( "k8s.io/kops/util/pkg/vfs" "k8s.io/kubernetes/pkg/util/mount" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/blang/semver" "k8s.io/klog" ) @@ -534,25 +538,40 @@ func EvaluateHostnameOverride(hostnameOverride string) (string, error) { return hostnameOverride, nil } - // We recognize @aws as meaning "the local-hostname from the aws metadata service" - vBytes, err := vfs.Context.ReadFile("metadata://aws/meta-data/local-hostname") + // We recognize @aws as meaning "the private DNS name from AWS", to generate this we need to get a few pieces of information + azBytes, err := vfs.Context.ReadFile("metadata://aws/meta-data/placement/availability-zone") if err != nil { - return "", fmt.Errorf("error reading local hostname from AWS metadata: %v", err) + return "", fmt.Errorf("error reading availability zone from AWS metadata: %v", err) } - // The local-hostname gets it's hostname from the AWS DHCP Option Set, which - // may provide multiple hostnames separated by spaces. For now just choose - // the first one as the hostname. - domains := strings.Fields(string(vBytes)) - if len(domains) == 0 { - klog.Warningf("Local hostname from AWS metadata service was empty") - return "", nil + instanceIDBytes, err := vfs.Context.ReadFile("metadata://aws/meta-data/instance-id") + if err != nil { + return "", fmt.Errorf("error reading instance-id from AWS metadata: %v", err) + } + instanceID := string(instanceIDBytes) + + config := aws.NewConfig() + config = config.WithCredentialsChainVerboseErrors(true) + + s, err := session.NewSession(config) + if err != nil { + return "", fmt.Errorf("error starting new AWS session: %v", err) } - domain := domains[0] - klog.Infof("Using hostname from AWS metadata service: %s", domain) + svc := ec2.New(s, config.WithRegion(string(azBytes[:len(azBytes)-1]))) + + result, err := svc.DescribeInstances(&ec2.DescribeInstancesInput{ + InstanceIds: []*string{&instanceID}, + }) + + if len(result.Reservations) != 1 { + return "", fmt.Errorf("Too many reservations returned for the single instance-id") + } - return domain, nil + if len(result.Reservations[0].Instances) != 1 { + return "", fmt.Errorf("Too many instances returned for the single instance-id") + } + return *(result.Reservations[0].Instances[0].PrivateDnsName), nil } // FindCert is a helper method to retrieving a certificate from the store diff --git a/upup/pkg/fi/nodeup/command.go b/upup/pkg/fi/nodeup/command.go index a5ebd516eb293..e899750f203bb 100644 --- a/upup/pkg/fi/nodeup/command.go +++ b/upup/pkg/fi/nodeup/command.go @@ -441,25 +441,40 @@ func evaluateHostnameOverride(hostnameOverride string) (string, error) { k = strings.ToLower(k) if k == "@aws" { - // We recognize @aws as meaning "the local-hostname from the aws metadata service" - vBytes, err := vfs.Context.ReadFile("metadata://aws/meta-data/local-hostname") + // We recognize @aws as meaning "the private DNS name from AWS", to generate this we need to get a few pieces of information + azBytes, err := vfs.Context.ReadFile("metadata://aws/meta-data/placement/availability-zone") if err != nil { - return "", fmt.Errorf("error reading local hostname from AWS metadata: %v", err) + return "", fmt.Errorf("error reading availability zone from AWS metadata: %v", err) } - // The local-hostname gets it's hostname from the AWS DHCP Option Set, which - // may provide multiple hostnames separated by spaces. For now just choose - // the first one as the hostname. - domains := strings.Fields(string(vBytes)) - if len(domains) == 0 { - klog.Warningf("Local hostname from AWS metadata service was empty") - return "", nil + instanceIDBytes, err := vfs.Context.ReadFile("metadata://aws/meta-data/instance-id") + if err != nil { + return "", fmt.Errorf("error reading instance-id from AWS metadata: %v", err) + } + instanceID := string(instanceIDBytes) + + config := aws.NewConfig() + config = config.WithCredentialsChainVerboseErrors(true) + + s, err := session.NewSession(config) + if err != nil { + return "", fmt.Errorf("error starting new AWS session: %v", err) } - domain := domains[0] - klog.Infof("Using hostname from AWS metadata service: %s", domain) + svc := ec2.New(s, config.WithRegion(string(azBytes[:len(azBytes)-1]))) + + result, err := svc.DescribeInstances(&ec2.DescribeInstancesInput{ + InstanceIds: []*string{&instanceID}, + }) - return domain, nil + if len(result.Reservations) != 1 { + return "", fmt.Errorf("Too many reservations returned for the single instance-id") + } + + if len(result.Reservations[0].Instances) != 1 { + return "", fmt.Errorf("Too many instances returned for the single instance-id") + } + return *(result.Reservations[0].Instances[0].PrivateDnsName), nil } if k == "@digitalocean" {