github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/client/fingerprint/env_aws.go (about)

     1  package fingerprint
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"net/url"
     7  	"os"
     8  	"regexp"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/aws/aws-sdk-go/aws"
    13  	"github.com/aws/aws-sdk-go/aws/awserr"
    14  	"github.com/aws/aws-sdk-go/aws/ec2metadata"
    15  	"github.com/aws/aws-sdk-go/aws/session"
    16  	log "github.com/hashicorp/go-hclog"
    17  
    18  	cleanhttp "github.com/hashicorp/go-cleanhttp"
    19  	"github.com/hashicorp/nomad/nomad/structs"
    20  )
    21  
    22  const (
    23  	// AwsMetadataTimeout is the timeout used when contacting the AWS metadata
    24  	// services.
    25  	AwsMetadataTimeout = 2 * time.Second
    26  )
    27  
    28  // map of instance type to approximate speed, in Mbits/s
    29  // Estimates from http://stackoverflow.com/a/35806587
    30  // This data is meant for a loose approximation
    31  var ec2NetSpeedTable = map[*regexp.Regexp]int{
    32  	regexp.MustCompile("t2.nano"):      30,
    33  	regexp.MustCompile("t2.micro"):     70,
    34  	regexp.MustCompile("t2.small"):     125,
    35  	regexp.MustCompile("t2.medium"):    300,
    36  	regexp.MustCompile("m3.medium"):    400,
    37  	regexp.MustCompile("c4.8xlarge"):   4000,
    38  	regexp.MustCompile("x1.16xlarge"):  5000,
    39  	regexp.MustCompile(`.*\.large`):    500,
    40  	regexp.MustCompile(`.*\.xlarge`):   750,
    41  	regexp.MustCompile(`.*\.2xlarge`):  1000,
    42  	regexp.MustCompile(`.*\.4xlarge`):  2000,
    43  	regexp.MustCompile(`.*\.8xlarge`):  10000,
    44  	regexp.MustCompile(`.*\.10xlarge`): 10000,
    45  	regexp.MustCompile(`.*\.16xlarge`): 10000,
    46  	regexp.MustCompile(`.*\.32xlarge`): 10000,
    47  }
    48  
    49  type ec2Specs struct {
    50  	mhz   float64
    51  	cores int
    52  	model string
    53  }
    54  
    55  func (e ec2Specs) ticks() int {
    56  	return int(e.mhz) * e.cores
    57  }
    58  
    59  func specs(ghz float64, vCores int, model string) ec2Specs {
    60  	return ec2Specs{
    61  		mhz:   ghz * 1000,
    62  		cores: vCores,
    63  		model: model,
    64  	}
    65  }
    66  
    67  // Map of instance type to documented CPU speed.
    68  //
    69  // Most values are taken from https://aws.amazon.com/ec2/instance-types/.
    70  // Values for a1 & m6g (Graviton) are taken from https://en.wikichip.org/wiki/annapurna_labs/alpine/al73400
    71  // Values for inf1 are taken from launching a inf1.xlarge and looking at /proc/cpuinfo
    72  //
    73  // In a few cases, AWS has upgraded the generation of CPU while keeping the same
    74  // instance designation. Since it is possible to launch on the lower performance
    75  // CPU, that one is used as the spec for the instance type.
    76  //
    77  // This table is provided as a best-effort to determine the number of CPU ticks
    78  // available for use by Nomad tasks. If an instance type is missing, the fallback
    79  // behavior is to use values from go-psutil, which is only capable of reading
    80  // "current" CPU MHz.
    81  var ec2ProcSpeedTable = map[string]ec2Specs{
    82  	// -- General Purpose --
    83  
    84  	// a1
    85  	"a1.medium":  specs(2.3, 1, "AWS Graviton"),
    86  	"a1.large":   specs(2.3, 2, "AWS Graviton"),
    87  	"a1.xlarge":  specs(2.3, 4, "AWS Graviton"),
    88  	"a1.2xlarge": specs(2.3, 8, "AWS Graviton"),
    89  	"a1.4xlarge": specs(2.3, 16, "AWS Graviton"),
    90  	"a1.metal":   specs(2.3, 16, "AWS Graviton"),
    91  
    92  	// t3
    93  	"t3.nano":    specs(2.5, 2, "2.5 GHz Intel Scalable"),
    94  	"t3.micro":   specs(2.5, 2, "2.5 GHz Intel Scalable"),
    95  	"t3.small":   specs(2.5, 2, "2.5 GHz Intel Scalable"),
    96  	"t3.medium":  specs(2.5, 2, "2.5 GHz Intel Scalable"),
    97  	"t3.large":   specs(2.5, 2, "2.5 GHz Intel Scalable"),
    98  	"t3.xlarge":  specs(2.5, 4, "2.5 GHz Intel Scalable"),
    99  	"t3.2xlarge": specs(2.5, 8, "2.5 GHz Intel Scalable"),
   100  
   101  	// t3a
   102  	"t3a.nano":    specs(2.5, 2, "2.5 GHz AMD EPYC 7000 series"),
   103  	"t3a.micro":   specs(2.5, 2, "2.5 GHz AMD EPYC 7000 series"),
   104  	"t3a.small":   specs(2.5, 2, "2.5 GHz AMD EPYC 7000 series"),
   105  	"t3a.medium":  specs(2.5, 2, "2.5 GHz AMD EPYC 7000 series"),
   106  	"t3a.large":   specs(2.5, 2, "2.5 GHz AMD EPYC 7000 series"),
   107  	"t3a.xlarge":  specs(2.5, 4, "2.5 GHz AMD EPYC 7000 series"),
   108  	"t3a.2xlarge": specs(2.5, 8, "2.5 GHz AMD EPYC 7000 series"),
   109  
   110  	// t2
   111  	"t2.nano":    specs(3.3, 1, "3.3 GHz Intel Scalable"),
   112  	"t2.micro":   specs(3.3, 1, "3.3 GHz Intel Scalable"),
   113  	"t2.small":   specs(3.3, 1, "3.3 GHz Intel Scalable"),
   114  	"t2.medium":  specs(3.3, 2, "3.3 GHz Intel Scalable"),
   115  	"t2.large":   specs(3.0, 2, "3.0 GHz Intel Scalable"),
   116  	"t2.xlarge":  specs(3.0, 4, "3.0 GHz Intel Scalable"),
   117  	"t2.2xlarge": specs(3.0, 8, "3.0 GHz Intel Scalable"),
   118  
   119  	// m6g
   120  	"m6g.medium":   specs(2.3, 1, "AWS Graviton2 Neoverse"),
   121  	"m6g.large":    specs(2.3, 2, "AWS Graviton2 Neoverse"),
   122  	"m6g.xlarge":   specs(2.3, 4, "AWS Graviton2 Neoverse"),
   123  	"m6g.2xlarge":  specs(2.3, 8, "AWS Graviton2 Neoverse"),
   124  	"m6g.4xlarge":  specs(2.3, 16, "AWS Graviton2 Neoverse"),
   125  	"m6g.8xlarge":  specs(2.3, 32, "AWS Graviton2 Neoverse"),
   126  	"m6g.12xlarge": specs(2.3, 48, "AWS Graviton2 Neoverse"),
   127  	"m6g.16xlarge": specs(2.3, 64, "AWS Graviton2 Neoverse"),
   128  
   129  	// m5, m5d
   130  	"m5.large":     specs(3.1, 2, "3.1 GHz Intel Xeon Platinum"),
   131  	"m5.xlarge":    specs(3.1, 4, "3.1 GHz Intel Xeon Platinum"),
   132  	"m5.2xlarge":   specs(3.1, 8, "3.1 GHz Intel Xeon Platinum"),
   133  	"m5.4xlarge":   specs(3.1, 16, "3.1 GHz Intel Xeon Platinum"),
   134  	"m5.8xlarge":   specs(3.1, 32, "3.1 GHz Intel Xeon Platinum"),
   135  	"m5.12xlarge":  specs(3.1, 48, "3.1 GHz Intel Xeon Platinum"),
   136  	"m5.16xlarge":  specs(3.1, 64, "3.1 GHz Intel Xeon Platinum"),
   137  	"m5.24xlarge":  specs(3.1, 96, "3.1 GHz Intel Xeon Platinum"),
   138  	"m5.metal":     specs(3.1, 96, "3.1 GHz Intel Xeon Platinum"),
   139  	"m5d.large":    specs(3.1, 2, "3.1 GHz Intel Xeon Platinum"),
   140  	"m5d.xlarge":   specs(3.1, 4, "3.1 GHz Intel Xeon Platinum"),
   141  	"m5d.2xlarge":  specs(3.1, 8, "3.1 GHz Intel Xeon Platinum"),
   142  	"m5d.4xlarge":  specs(3.1, 16, "3.1 GHz Intel Xeon Platinum"),
   143  	"m5d.8xlarge":  specs(3.1, 32, "3.1 GHz Intel Xeon Platinum"),
   144  	"m5d.12xlarge": specs(3.1, 48, "3.1 GHz Intel Xeon Platinum"),
   145  	"m5d.16xlarge": specs(3.1, 64, "3.1 GHz Intel Xeon Platinum"),
   146  	"m5d.24xlarge": specs(3.1, 96, "3.1 GHz Intel Xeon Platinum"),
   147  	"m5d.metal":    specs(3.1, 96, "3.1 GHz Intel Xeon Platinum"),
   148  
   149  	// m5a, m5ad
   150  	"m5a.large":     specs(2.5, 2, "2.5 GHz AMD EPYC 7000 series"),
   151  	"m5a.xlarge":    specs(2.5, 4, "2.5 GHz AMD EPYC 7000 series"),
   152  	"m5a.2xlarge":   specs(2.5, 8, "2.5 GHz AMD EPYC 7000 series"),
   153  	"m5a.4xlarge":   specs(2.5, 16, "2.5 GHz AMD EPYC 7000 series"),
   154  	"m5a.8xlarge":   specs(2.5, 32, "2.5 GHz AMD EPYC 7000 series"),
   155  	"m5a.12xlarge":  specs(2.5, 48, "2.5 GHz AMD EPYC 7000 series"),
   156  	"m5a.16xlarge":  specs(2.5, 64, "2.5 GHz AMD EPYC 7000 series"),
   157  	"m5a.24xlarge":  specs(2.5, 96, "2.5 GHz AMD EPYC 7000 series"),
   158  	"m5ad.large":    specs(2.5, 2, "2.5 GHz AMD EPYC 7000 series"),
   159  	"m5ad.xlarge":   specs(2.5, 4, "2.5 GHz AMD EPYC 7000 series"),
   160  	"m5ad.2xlarge":  specs(2.5, 8, "2.5 GHz AMD EPYC 7000 series"),
   161  	"m5ad.4xlarge":  specs(2.5, 16, "2.5 GHz AMD EPYC 7000 series"),
   162  	"m5ad.12xlarge": specs(2.5, 48, "2.5 GHz AMD EPYC 7000 series"),
   163  	"m5ad.24xlarge": specs(2.5, 96, "2.5 GHz AMD EPYC 7000 series"),
   164  
   165  	// m5n, m5dn
   166  	"m5n.large":     specs(3.1, 2, "3.1 GHz Intel Xeon Scalable"),
   167  	"m5n.xlarge":    specs(3.1, 4, "3.1 GHz Intel Xeon Scalable"),
   168  	"m5n.2xlarge":   specs(3.1, 8, "3.1 GHz Intel Xeon Scalable"),
   169  	"m5n.4xlarge":   specs(3.1, 16, "3.1 GHz Intel Xeon Scalable"),
   170  	"m5n.8xlarge":   specs(3.1, 32, "3.1 GHz Intel Xeon Scalable"),
   171  	"m5n.12xlarge":  specs(3.1, 48, "3.1 GHz Intel Xeon Scalable"),
   172  	"m5n.16xlarge":  specs(3.1, 64, "3.1 GHz Intel Xeon Scalable"),
   173  	"m5n.24xlarge":  specs(3.1, 96, "3.1 GHz Intel Xeon Scalable"),
   174  	"m5dn.large":    specs(3.1, 2, "3.1 GHz Intel Xeon Scalable"),
   175  	"m5dn.xlarge":   specs(3.1, 4, "3.1 GHz Intel Xeon Scalable"),
   176  	"m5dn.2xlarge":  specs(3.1, 8, "3.1 GHz Intel Xeon Scalable"),
   177  	"m5dn.4xlarge":  specs(3.1, 16, "3.1 GHz Intel Xeon Scalable"),
   178  	"m5dn.8xlarge":  specs(3.1, 32, "3.1 GHz Intel Xeon Scalable"),
   179  	"m5dn.12xlarge": specs(3.1, 48, "3.1 GHz Intel Xeon Scalable"),
   180  	"m5dn.16xlarge": specs(3.1, 64, "3.1 GHz Intel Xeon Scalable"),
   181  	"m5dn.24xlarge": specs(3.1, 96, "3.1 GHz Intel Xeon Scalable"),
   182  
   183  	// m4
   184  	"m4.large":    specs(2.3, 2, "2.3 GHz Intel Xeon® E5-2686 v4"),
   185  	"m4.xlarge":   specs(2.3, 4, "2.3 GHz Intel Xeon® E5-2686 v4"),
   186  	"m4.2xlarge":  specs(2.3, 8, "2.3 GHz Intel Xeon® E5-2686 v4"),
   187  	"m4.4xlarge":  specs(2.3, 16, "2.3 GHz Intel Xeon® E5-2686 v4"),
   188  	"m4.10xlarge": specs(2.3, 40, "2.3 GHz Intel Xeon® E5-2686 v4"),
   189  	"m4.16xlarge": specs(2.3, 64, "2.3 GHz Intel Xeon® E5-2686 v4"),
   190  
   191  	// -- Compute Optimized --
   192  
   193  	// c5, c5d
   194  	"c5.large":     specs(3.4, 2, "3.4 GHz Intel Xeon Platinum 8000"),
   195  	"c5.xlarge":    specs(3.4, 4, "3.4 GHz Intel Xeon Platinum 8000"),
   196  	"c5.2xlarge":   specs(3.4, 8, "3.4 GHz Intel Xeon Platinum 8000"),
   197  	"c5.4xlarge":   specs(3.4, 16, "3.4 GHz Intel Xeon Platinum 8000"),
   198  	"c5.9xlarge":   specs(3.4, 36, "3.4 GHz Intel Xeon Platinum 8000"),
   199  	"c5.12xlarge":  specs(3.6, 48, "3.6 GHz Intel Xeon Scalable"),
   200  	"c5.18xlarge":  specs(3.6, 72, "3.6 GHz Intel Xeon Scalable"),
   201  	"c5.24xlarge":  specs(3.6, 96, "3.6 GHz Intel Xeon Scalable"),
   202  	"c5.metal":     specs(3.6, 96, "3.6 GHz Intel Xeon Scalable"),
   203  	"c5d.large":    specs(3.4, 2, "3.4 GHz Intel Xeon Platinum 8000"),
   204  	"c5d.xlarge":   specs(3.4, 4, "3.4 GHz Intel Xeon Platinum 8000"),
   205  	"c5d.2xlarge":  specs(3.4, 8, "3.4 GHz Intel Xeon Platinum 8000"),
   206  	"c5d.4xlarge":  specs(3.4, 16, "3.4 GHz Intel Xeon Platinum 8000"),
   207  	"c5d.9xlarge":  specs(3.4, 36, "3.4 GHz Intel Xeon Platinum 8000"),
   208  	"c5d.12xlarge": specs(3.6, 48, "3.6 GHz Intel Xeon Scalable"),
   209  	"c5d.18xlarge": specs(3.6, 72, "3.6 GHz Intel Xeon Scalable"),
   210  	"c5d.24xlarge": specs(3.6, 96, "3.6 GHz Intel Xeon Scalable"),
   211  	"c5d.metal":    specs(3.6, 96, "3.6 GHz Intel Xeon Scalable"),
   212  
   213  	// c5n
   214  	"c5n.large":    specs(3.0, 2, "3.0 GHz Intel Xeon Platinum"),
   215  	"c5n.xlarge":   specs(3.0, 4, "3.0 GHz Intel Xeon Platinum"),
   216  	"c5n.2xlarge":  specs(3.0, 8, "3.0 GHz Intel Xeon Platinum"),
   217  	"c5n.4xlarge":  specs(3.0, 16, "3.0 GHz Intel Xeon Platinum"),
   218  	"c5n.9xlarge":  specs(3.0, 36, "3.0 GHz Intel Xeon Platinum"),
   219  	"c5n.18xlarge": specs(3.0, 72, "3.0 GHz Intel Xeon Platinum"),
   220  	"c5n.metal":    specs(3.0, 72, "3.0 GHz Intel Xeon Platinum"),
   221  
   222  	// c4
   223  	"c4.large":   specs(2.9, 2, "2.9 GHz Intel Xeon E5-2666 v3"),
   224  	"c4.xlarge":  specs(2.9, 4, "2.9 GHz Intel Xeon E5-2666 v3"),
   225  	"c4.2xlarge": specs(2.9, 8, "2.9 GHz Intel Xeon E5-2666 v3"),
   226  	"c4.4xlarge": specs(2.9, 16, "2.9 GHz Intel Xeon E5-2666 v3"),
   227  	"c4.8xlarge": specs(2.9, 36, "2.9 GHz Intel Xeon E5-2666 v3"),
   228  
   229  	// -- Memory Optimized --
   230  
   231  	// r5, r5d
   232  	"r5.large":     specs(3.1, 2, "3.1 GHz Intel Xeon Platinum 8175"),
   233  	"r5.xlarge":    specs(3.1, 4, "3.1 GHz Intel Xeon Platinum 8175"),
   234  	"r5.2xlarge":   specs(3.1, 8, "3.1 GHz Intel Xeon Platinum 8175"),
   235  	"r5.4xlarge":   specs(3.1, 16, "3.1 GHz Intel Xeon Platinum 8175"),
   236  	"r5.8xlarge":   specs(3.1, 32, "3.1 GHz Intel Xeon Platinum 8175"),
   237  	"r5.12xlarge":  specs(3.1, 48, "3.1 GHz Intel Xeon Platinum 8175"),
   238  	"r5.16xlarge":  specs(3.1, 64, "3.1 GHz Intel Xeon Platinum 8175"),
   239  	"r5.24xlarge":  specs(3.1, 96, "3.1 GHz Intel Xeon Platinum 8175"),
   240  	"r5.metal":     specs(3.1, 96, "3.1 GHz Intel Xeon Platinum 8175"),
   241  	"r5d.large":    specs(3.1, 2, "3.1 GHz Intel Xeon Platinum 8175"),
   242  	"r5d.xlarge":   specs(3.1, 4, "3.1 GHz Intel Xeon Platinum 8175"),
   243  	"r5d.2xlarge":  specs(3.1, 8, "3.1 GHz Intel Xeon Platinum 8175"),
   244  	"r5d.4xlarge":  specs(3.1, 16, "3.1 GHz Intel Xeon Platinum 8175"),
   245  	"r5d.8xlarge":  specs(3.1, 32, "3.1 GHz Intel Xeon Platinum 8175"),
   246  	"r5d.12xlarge": specs(3.1, 48, "3.1 GHz Intel Xeon Platinum 8175"),
   247  	"r5d.16xlarge": specs(3.1, 64, "3.1 GHz Intel Xeon Platinum 8175"),
   248  	"r5d.24xlarge": specs(3.1, 96, "3.1 GHz Intel Xeon Platinum 8175"),
   249  	"r5d.metal":    specs(3.1, 96, "3.1 GHz Intel Xeon Platinum 8175"),
   250  
   251  	// r5a, r5ad
   252  	"r5a.large":     specs(2.5, 2, "2.5 GHz AMD EPYC 7000 series"),
   253  	"r5a.xlarge":    specs(2.5, 4, "2.5 GHz AMD EPYC 7000 series"),
   254  	"r5a.2xlarge":   specs(2.5, 8, "2.5 GHz AMD EPYC 7000 series"),
   255  	"r5a.4xlarge":   specs(2.5, 16, "2.5 GHz AMD EPYC 7000 series"),
   256  	"r5a.8xlarge":   specs(2.5, 32, "2.5 GHz AMD EPYC 7000 series"),
   257  	"r5a.12xlarge":  specs(2.5, 48, "2.5 GHz AMD EPYC 7000 series"),
   258  	"r5a.16xlarge":  specs(2.5, 64, "2.5 GHz AMD EPYC 7000 series"),
   259  	"r5a.24xlarge":  specs(2.5, 96, "2.5 GHz AMD EPYC 7000 series"),
   260  	"r5ad.large":    specs(2.5, 2, "2.5 GHz AMD EPYC 7000 series"),
   261  	"r5ad.xlarge":   specs(2.5, 4, "2.5 GHz AMD EPYC 7000 series"),
   262  	"r5ad.2xlarge":  specs(2.5, 8, "2.5 GHz AMD EPYC 7000 series"),
   263  	"r5ad.4xlarge":  specs(2.5, 16, "2.5 GHz AMD EPYC 7000 series"),
   264  	"r5ad.8xlarge":  specs(2.5, 32, "2.5 GHz AMD EPYC 7000 series"),
   265  	"r5ad.12xlarge": specs(2.5, 48, "2.5 GHz AMD EPYC 7000 series"),
   266  	"r5ad.16xlarge": specs(2.5, 64, "2.5 GHz AMD EPYC 7000 series"),
   267  	"r5ad.24xlarge": specs(2.5, 96, "2.5 GHz AMD EPYC 7000 series"),
   268  
   269  	// r5n
   270  	"r5n.large":     specs(3.1, 2, "3.1 GHz Intel Xeon Scalable"),
   271  	"r5n.xlarge":    specs(3.1, 4, "3.1 GHz Intel Xeon Scalable"),
   272  	"r5n.2xlarge":   specs(3.1, 8, "3.1 GHz Intel Xeon Scalable"),
   273  	"r5n.4xlarge":   specs(3.1, 16, "3.1 GHz Intel Xeon Scalable"),
   274  	"r5n.8xlarge":   specs(3.1, 32, "3.1 GHz Intel Xeon Scalable"),
   275  	"r5n.12xlarge":  specs(3.1, 48, "3.1 GHz Intel Xeon Scalable"),
   276  	"r5n.16xlarge":  specs(3.1, 64, "3.1 GHz Intel Xeon Scalable"),
   277  	"r5n.24xlarge":  specs(3.1, 96, "3.1 GHz Intel Xeon Scalable"),
   278  	"r5dn.large":    specs(3.1, 2, "3.1 GHz Intel Xeon Scalable"),
   279  	"r5dn.xlarge":   specs(3.1, 4, "3.1 GHz Intel Xeon Scalable"),
   280  	"r5dn.2xlarge":  specs(3.1, 8, "3.1 GHz Intel Xeon Scalable"),
   281  	"r5dn.4xlarge":  specs(3.1, 16, "3.1 GHz Intel Xeon Scalable"),
   282  	"r5dn.8xlarge":  specs(3.1, 32, "3.1 GHz Intel Xeon Scalable"),
   283  	"r5dn.12xlarge": specs(3.1, 48, "3.1 GHz Intel Xeon Scalable"),
   284  	"r5dn.16xlarge": specs(3.1, 64, "3.1 GHz Intel Xeon Scalable"),
   285  	"r5dn.24xlarge": specs(3.1, 96, "3.1 GHz Intel Xeon Scalable"),
   286  
   287  	// r4
   288  	"r4.large":    specs(2.3, 2, "2.3 GHz Intel Xeon E5-2686 v4"),
   289  	"r4.xlarge":   specs(2.3, 4, "2.3 GHz Intel Xeon E5-2686 v4"),
   290  	"r4.2xlarge":  specs(2.3, 8, "2.3 GHz Intel Xeon E5-2686 v4"),
   291  	"r4.4xlarge":  specs(2.3, 16, "2.3 GHz Intel Xeon E5-2686 v4"),
   292  	"r4.8xlarge":  specs(2.3, 32, "2.3 GHz Intel Xeon E5-2686 v4"),
   293  	"r4.16xlarge": specs(2.3, 64, "2.3 GHz Intel Xeon E5-2686 v4"),
   294  
   295  	// x1e
   296  	"x1e.xlarge":   specs(2.3, 4, "2.3 GHz Intel Xeon E7-8880 v3"),
   297  	"x1e.2xlarge":  specs(2.3, 8, "2.3 GHz Intel Xeon E7-8880 v3"),
   298  	"x1e.4xlarge":  specs(2.3, 16, "2.3 GHz Intel Xeon E7-8880 v3"),
   299  	"x1e.8xlarge":  specs(2.3, 32, "2.3 GHz Intel Xeon E7-8880 v3"),
   300  	"x1e.16xlarge": specs(2.3, 64, "2.3 GHz Intel Xeon E7-8880 v3"),
   301  	"x1e.32xlarge": specs(2.3, 128, "2.3 GHz Intel Xeon E7-8880 v3"),
   302  
   303  	// x1
   304  	"x1.16xlarge": specs(2.3, 64, "2.3 GHz Intel Xeon E7-8880 v3"),
   305  	"x1.32xlarge": specs(2.3, 64, "2.3 GHz Intel Xeon E7-8880 v3"),
   306  
   307  	// high-memory
   308  	"u-6tb1.metal":  specs(2.1, 448, "2.1 GHz Intel Xeon Platinum 8176M"),
   309  	"u-9tb1.metal":  specs(2.1, 448, "2.1 GHz Intel Xeon Platinum 8176M"),
   310  	"u-12tb1.metal": specs(2.1, 448, "2.1 GHz Intel Xeon Platinum 8176M"),
   311  	"u-18tb1.metal": specs(2.7, 448, "2.7 GHz Intel Xeon Scalable"),
   312  	"u-24tb1.metal": specs(2.7, 448, "2.7 GHz Intel Xeon Scalable"),
   313  
   314  	// z1d
   315  	"z1d.large":    specs(4.0, 2, "4.0 GHz Intel Xeon Scalable"),
   316  	"z1d.xlarge":   specs(4.0, 4, "4.0 GHz Intel Xeon Scalable"),
   317  	"z1d.2xlarge":  specs(4.0, 8, "4.0 GHz Intel Xeon Scalable"),
   318  	"z1d.3xlarge":  specs(4.0, 12, "4.0 GHz Intel Xeon Scalable"),
   319  	"z1d.6xlarge":  specs(4.0, 24, "4.0 GHz Intel Xeon Scalable"),
   320  	"z1d.12xlarge": specs(4.0, 48, "4.0 GHz Intel Xeon Scalable"),
   321  	"z1d.metal":    specs(4.0, 48, "4.0 GHz Intel Xeon Scalable"),
   322  
   323  	// -- Accelerated Computing --
   324  
   325  	// p3, p3dn
   326  	"p3.2xlarge":    specs(2.3, 8, "2.3 GHz Intel Xeon E5-2686 v4"),
   327  	"p3.8xlarge":    specs(2.3, 32, "2.3 GHz Intel Xeon E5-2686 v4"),
   328  	"p3.16xlarge":   specs(2.3, 64, "2.3 GHz Intel Xeon E5-2686 v4"),
   329  	"p3dn.24xlarge": specs(2.5, 96, "2.5 GHz Intel Xeon P-8175M"),
   330  
   331  	// p2
   332  	"p2.xlarge":   specs(2.3, 4, "2.3 GHz Intel Xeon E5-2686 v4"),
   333  	"p2.8xlarge":  specs(2.3, 32, "2.3 GHz Intel Xeon E5-2686 v4"),
   334  	"p2.16xlarge": specs(2.3, 64, "2.3 GHz Intel Xeon E5-2686 v4"),
   335  
   336  	// inf1
   337  	"inf1.xlarge":   specs(3.0, 4, "3.0 GHz Intel Xeon Platinum 8275CL"),
   338  	"inf1.2xlarge":  specs(3.0, 8, "3.0 GHz Intel Xeon Platinum 8275CL"),
   339  	"inf1.6xlarge":  specs(3.0, 24, "3.0 GHz Intel Xeon Platinum 8275CL"),
   340  	"inf1.24xlarge": specs(3.0, 96, "3.0 GHz Intel Xeon Platinum 8275CL"),
   341  
   342  	// g4dn
   343  	"g4dn.xlarge":   specs(2.5, 4, "2.5 GHz Cascade Lake 24C"),
   344  	"g4dn.2xlarge":  specs(2.5, 8, "2.5 GHz Cascade Lake 24C"),
   345  	"g4dn.4xlarge":  specs(2.5, 16, "2.5 GHz Cascade Lake 24C"),
   346  	"g4dn.8xlarge":  specs(2.5, 32, "2.5 GHz Cascade Lake 24C"),
   347  	"g4dn.16xlarge": specs(2.5, 64, "2.5 GHz Cascade Lake 24C"),
   348  	"g4dn.12xlarge": specs(2.5, 48, "2.5 GHz Cascade Lake 24C"),
   349  	"g4dn.metal":    specs(2.5, 96, "2.5 GHz Cascade Lake 24C"),
   350  
   351  	// g3
   352  	"g3s.xlarge":   specs(2.3, 4, "2.3 GHz Intel Xeon E5-2686 v4"),
   353  	"g3s.4xlarge":  specs(2.3, 16, "2.3 GHz Intel Xeon E5-2686 v4"),
   354  	"g3s.8xlarge":  specs(2.3, 32, "2.3 GHz Intel Xeon E5-2686 v4"),
   355  	"g3s.16xlarge": specs(2.3, 64, "2.3 GHz Intel Xeon E5-2686 v4"),
   356  
   357  	// f1
   358  	"f1.2xlarge":  specs(2.3, 8, "Intel Xeon E5-2686 v4"),
   359  	"f1.4xlarge":  specs(2.3, 16, "Intel Xeon E5-2686 v4"),
   360  	"f1.16xlarge": specs(2.3, 64, "Intel Xeon E5-2686 v4"),
   361  
   362  	// -- Storage Optimized --
   363  
   364  	// i3
   365  	"i3.large":    specs(2.3, 2, "2.3 GHz Intel Xeon E5 2686 v4"),
   366  	"i3.xlarge":   specs(2.3, 4, "2.3 GHz Intel Xeon E5 2686 v4"),
   367  	"i3.2xlarge":  specs(2.3, 8, "2.3 GHz Intel Xeon E5 2686 v4"),
   368  	"i3.4xlarge":  specs(2.3, 16, "2.3 GHz Intel Xeon E5 2686 v4"),
   369  	"i3.8xlarge":  specs(2.3, 32, "2.3 GHz Intel Xeon E5 2686 v4"),
   370  	"i3.16xlarge": specs(2.3, 64, "2.3 GHz Intel Xeon E5 2686 v4"),
   371  	"i3.metal":    specs(2.3, 72, "2.3 GHz Intel Xeon E5 2686 v4"),
   372  
   373  	// i3en
   374  	"i3en.large":    specs(3.1, 2, "3.1 GHz Intel Xeon Scalable"),
   375  	"i3en.xlarge":   specs(3.1, 4, "3.1 GHz Intel Xeon Scalable"),
   376  	"i3en.2xlarge":  specs(3.1, 8, "3.1 GHz Intel Xeon Scalable"),
   377  	"i3en.3xlarge":  specs(3.1, 12, "3.1 GHz Intel Xeon Scalable"),
   378  	"i3en.6xlarge":  specs(3.1, 24, "3.1 GHz Intel Xeon Scalable"),
   379  	"i3en.12xlarge": specs(3.1, 48, "3.1 GHz Intel Xeon Scalable"),
   380  	"i3en.24xlarge": specs(3.1, 96, "3.1 GHz Intel Xeon Scalable"),
   381  	"i3en.metal":    specs(3.1, 96, "3.1 GHz Intel Xeon Scalable"),
   382  
   383  	// d2
   384  	"d2.xlarge":  specs(2.4, 4, "2.4 GHz Intel Xeon E5-2676 v3"),
   385  	"d2.2xlarge": specs(2.4, 8, "2.4 GHz Intel Xeon E5-2676 v3"),
   386  	"d2.4xlarge": specs(2.4, 16, "2.4 GHz Intel Xeon E5-2676 v3"),
   387  	"d2.8xlarge": specs(2.4, 36, "2.4 GHz Intel Xeon E5-2676 v3"),
   388  
   389  	// h1
   390  	"h1.2xlarge":  specs(2.3, 8, "2.3 GHz Intel Xeon E5 2686 v4"),
   391  	"h1.4xlarge":  specs(2.3, 16, "2.3 GHz Intel Xeon E5 2686 v4"),
   392  	"h1.8xlarge":  specs(2.3, 32, "2.3 GHz Intel Xeon E5 2686 v4"),
   393  	"h1.16xlarge": specs(2.3, 64, "2.3 GHz Intel Xeon E5 2686 v4"),
   394  }
   395  
   396  // EnvAWSFingerprint is used to fingerprint AWS metadata
   397  type EnvAWSFingerprint struct {
   398  	StaticFingerprinter
   399  
   400  	// endpoint for EC2 metadata as expected by AWS SDK
   401  	endpoint string
   402  
   403  	logger log.Logger
   404  }
   405  
   406  // NewEnvAWSFingerprint is used to create a fingerprint from AWS metadata
   407  func NewEnvAWSFingerprint(logger log.Logger) Fingerprint {
   408  	f := &EnvAWSFingerprint{
   409  		logger:   logger.Named("env_aws"),
   410  		endpoint: strings.TrimSuffix(os.Getenv("AWS_ENV_URL"), "/meta-data/"),
   411  	}
   412  	return f
   413  }
   414  
   415  func (f *EnvAWSFingerprint) Fingerprint(request *FingerprintRequest, response *FingerprintResponse) error {
   416  	cfg := request.Config
   417  
   418  	timeout := AwsMetadataTimeout
   419  
   420  	// Check if we should tighten the timeout
   421  	if cfg.ReadBoolDefault(TightenNetworkTimeoutsConfig, false) {
   422  		timeout = 1 * time.Millisecond
   423  	}
   424  
   425  	ec2meta, err := ec2MetaClient(f.endpoint, timeout)
   426  	if err != nil {
   427  		return fmt.Errorf("failed to setup ec2Metadata client: %v", err)
   428  	}
   429  
   430  	if !isAWS(ec2meta) {
   431  		return nil
   432  	}
   433  
   434  	// Keys and whether they should be namespaced as unique. Any key whose value
   435  	// uniquely identifies a node, such as ip, should be marked as unique. When
   436  	// marked as unique, the key isn't included in the computed node class.
   437  	keys := map[string]bool{
   438  		"ami-id":                      false,
   439  		"hostname":                    true,
   440  		"instance-id":                 true,
   441  		"instance-type":               false,
   442  		"local-hostname":              true,
   443  		"local-ipv4":                  true,
   444  		"public-hostname":             true,
   445  		"public-ipv4":                 true,
   446  		"placement/availability-zone": false,
   447  	}
   448  
   449  	for k, unique := range keys {
   450  		resp, err := ec2meta.GetMetadata(k)
   451  		v := strings.TrimSpace(resp)
   452  		if v == "" {
   453  			f.logger.Debug("read an empty value", "attribute", k)
   454  			continue
   455  		} else if awsErr, ok := err.(awserr.RequestFailure); ok {
   456  			f.logger.Debug("could not read attribute value", "attribute", k, "error", awsErr)
   457  			continue
   458  		} else if awsErr, ok := err.(awserr.Error); ok {
   459  			// if it's a URL error, assume we're not in an AWS environment
   460  			// TODO: better way to detect AWS? Check xen virtualization?
   461  			if _, ok := awsErr.OrigErr().(*url.Error); ok {
   462  				return nil
   463  			}
   464  
   465  			// not sure what other errors it would return
   466  			return err
   467  		}
   468  
   469  		// assume we want blank entries
   470  		key := "platform.aws." + strings.Replace(k, "/", ".", -1)
   471  		if unique {
   472  			key = structs.UniqueNamespace(key)
   473  		}
   474  
   475  		response.AddAttribute(key, v)
   476  	}
   477  
   478  	// accumulate resource information, then assign to response
   479  	var resources *structs.Resources
   480  	var nodeResources *structs.NodeResources
   481  
   482  	// copy over network specific information
   483  	if val, ok := response.Attributes["unique.platform.aws.local-ipv4"]; ok && val != "" {
   484  		response.AddAttribute("unique.network.ip-address", val)
   485  		nodeResources = new(structs.NodeResources)
   486  		nodeResources.Networks = []*structs.NetworkResource{
   487  			{
   488  				Device: "eth0",
   489  				IP:     val,
   490  				CIDR:   val + "/32",
   491  				MBits:  f.throughput(request, ec2meta, val),
   492  			},
   493  		}
   494  	}
   495  
   496  	// copy over CPU speed information
   497  	if specs := f.lookupCPU(ec2meta); specs != nil {
   498  		response.AddAttribute("cpu.modelname", specs.model)
   499  		response.AddAttribute("cpu.frequency", fmt.Sprintf("%.0f", specs.mhz))
   500  		response.AddAttribute("cpu.numcores", fmt.Sprintf("%d", specs.cores))
   501  		f.logger.Debug("lookup ec2 cpu", "cores", specs.cores, "MHz", log.Fmt("%.0f", specs.mhz), "model", specs.model)
   502  
   503  		if ticks := specs.ticks(); request.Config.CpuCompute <= 0 {
   504  			response.AddAttribute("cpu.totalcompute", fmt.Sprintf("%d", ticks))
   505  			f.logger.Debug("setting ec2 cpu ticks", "ticks", ticks)
   506  			resources = new(structs.Resources)
   507  			resources.CPU = ticks
   508  			if nodeResources == nil {
   509  				nodeResources = new(structs.NodeResources)
   510  			}
   511  			nodeResources.Cpu = structs.NodeCpuResources{CpuShares: int64(ticks)}
   512  		}
   513  	} else {
   514  		f.logger.Warn("failed to find the cpu specification for this instance type")
   515  	}
   516  
   517  	response.Resources = resources
   518  	response.NodeResources = nodeResources
   519  
   520  	// populate Links
   521  	response.AddLink("aws.ec2", fmt.Sprintf("%s.%s",
   522  		response.Attributes["platform.aws.placement.availability-zone"],
   523  		response.Attributes["unique.platform.aws.instance-id"]))
   524  	response.Detected = true
   525  
   526  	return nil
   527  }
   528  
   529  func (f *EnvAWSFingerprint) instanceType(ec2meta *ec2metadata.EC2Metadata) (string, error) {
   530  	response, err := ec2meta.GetMetadata("instance-type")
   531  	if err != nil {
   532  		return "", err
   533  	}
   534  	return strings.TrimSpace(response), nil
   535  }
   536  
   537  func (f *EnvAWSFingerprint) lookupCPU(ec2meta *ec2metadata.EC2Metadata) *ec2Specs {
   538  	instanceType, err := f.instanceType(ec2meta)
   539  	if err != nil {
   540  		f.logger.Warn("failed to read EC2 metadata instance-type", "error", err)
   541  		return nil
   542  	}
   543  	for iType, specs := range ec2ProcSpeedTable {
   544  		if strings.EqualFold(iType, instanceType) {
   545  			return &specs
   546  		}
   547  	}
   548  	return nil
   549  }
   550  
   551  func (f *EnvAWSFingerprint) throughput(request *FingerprintRequest, ec2meta *ec2metadata.EC2Metadata, ip string) int {
   552  	throughput := request.Config.NetworkSpeed
   553  	if throughput != 0 {
   554  		return throughput
   555  	}
   556  
   557  	throughput = f.linkSpeed(ec2meta)
   558  	if throughput != 0 {
   559  		return throughput
   560  	}
   561  
   562  	if request.Node.Resources != nil && len(request.Node.Resources.Networks) > 0 {
   563  		for _, n := range request.Node.Resources.Networks {
   564  			if n.IP == ip {
   565  				return n.MBits
   566  			}
   567  		}
   568  	}
   569  
   570  	return defaultNetworkSpeed
   571  }
   572  
   573  // EnvAWSFingerprint uses lookup table to approximate network speeds
   574  func (f *EnvAWSFingerprint) linkSpeed(ec2meta *ec2metadata.EC2Metadata) int {
   575  	instanceType, err := f.instanceType(ec2meta)
   576  	if err != nil {
   577  		f.logger.Error("error reading instance-type", "error", err)
   578  		return 0
   579  	}
   580  
   581  	netSpeed := 0
   582  	for reg, speed := range ec2NetSpeedTable {
   583  		if reg.MatchString(instanceType) {
   584  			netSpeed = speed
   585  			break
   586  		}
   587  	}
   588  
   589  	return netSpeed
   590  }
   591  
   592  func ec2MetaClient(endpoint string, timeout time.Duration) (*ec2metadata.EC2Metadata, error) {
   593  	client := &http.Client{
   594  		Timeout:   timeout,
   595  		Transport: cleanhttp.DefaultTransport(),
   596  	}
   597  
   598  	c := aws.NewConfig().WithHTTPClient(client).WithMaxRetries(0)
   599  	if endpoint != "" {
   600  		c = c.WithEndpoint(endpoint)
   601  	}
   602  
   603  	sess, err := session.NewSession(c)
   604  	if err != nil {
   605  		return nil, err
   606  	}
   607  	return ec2metadata.New(sess, c), nil
   608  }
   609  
   610  func isAWS(ec2meta *ec2metadata.EC2Metadata) bool {
   611  	v, err := ec2meta.GetMetadata("ami-id")
   612  	v = strings.TrimSpace(v)
   613  	return err == nil && v != ""
   614  }