19320: Fix AWS InstanceStatus and SpotPrice API usage.
authorTom Clegg <tom@curii.com>
Wed, 18 Jan 2023 14:58:49 +0000 (09:58 -0500)
committerTom Clegg <tom@curii.com>
Wed, 18 Jan 2023 14:58:49 +0000 (09:58 -0500)
Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom@curii.com>

lib/cloud/ec2/ec2.go
lib/cloud/ec2/ec2_test.go

index f80e9bd1a52553421befdc4cc504382202328b55..2a5eea484590c646e8398762d5692a441f2dc15e 100644 (file)
@@ -297,12 +297,17 @@ func (instanceSet *ec2InstanceSet) Instances(tags cloud.InstanceTags) (instances
        }
        if needAZs {
                az := map[string]string{}
-               instanceSet.client.DescribeInstanceStatusPages(&ec2.DescribeInstanceStatusInput{}, func(page *ec2.DescribeInstanceStatusOutput, lastPage bool) bool {
+               err := instanceSet.client.DescribeInstanceStatusPages(&ec2.DescribeInstanceStatusInput{
+                       IncludeAllInstances: aws.Bool(true),
+               }, func(page *ec2.DescribeInstanceStatusOutput, lastPage bool) bool {
                        for _, ent := range page.InstanceStatuses {
                                az[*ent.InstanceId] = *ent.AvailabilityZone
                        }
                        return true
                })
+               if err != nil {
+                       instanceSet.logger.Warnf("error getting instance statuses: %s", err)
+               }
                for _, inst := range instances {
                        inst := inst.(*ec2Instance)
                        inst.availabilityZone = az[*inst.instance.InstanceId]
@@ -363,7 +368,8 @@ func (instanceSet *ec2InstanceSet) updateSpotPrices(instances []cloud.Instance)
        dsphi := &ec2.DescribeSpotPriceHistoryInput{
                StartTime: aws.Time(updateTime.Add(-3 * instanceSet.ec2config.SpotPriceUpdateInterval.Duration())),
                Filters: []*ec2.Filter{
-                       &ec2.Filter{Name: aws.String("InstanceType"), Values: typeFilterValues},
+                       &ec2.Filter{Name: aws.String("instance-type"), Values: typeFilterValues},
+                       &ec2.Filter{Name: aws.String("product-description"), Values: []*string{aws.String("Linux/UNIX")}},
                },
        }
        err := instanceSet.client.DescribeSpotPriceHistoryPages(dsphi, func(page *ec2.DescribeSpotPriceHistoryOutput, lastPage bool) bool {
@@ -503,11 +509,12 @@ func (inst *ec2Instance) VerifyHostKey(ssh.PublicKey, *ssh.Client) error {
 func (inst *ec2Instance) PriceHistory() []cloud.InstancePrice {
        inst.provider.pricesLock.Lock()
        defer inst.provider.pricesLock.Unlock()
-       return inst.provider.prices[priceKey{
+       pk := priceKey{
                instanceType:     *inst.instance.InstanceType,
                spot:             aws.StringValue(inst.instance.InstanceLifecycle) == "spot",
                availabilityZone: inst.availabilityZone,
-       }]
+       }
+       return inst.provider.prices[pk]
 }
 
 type rateLimitError struct {
index 10364225824811c2ad7509edbecd511eea9c3081..e7534a7b6925c3a13948439ec1e570a0193a43ef 100644 (file)
@@ -287,6 +287,16 @@ func (*EC2InstanceSetSuite) TestInstancePriceHistory(c *check.C) {
        ap, img, cluster := GetInstanceSet(c)
        pk, _ := test.LoadTestKey(c, "../../dispatchcloud/test/sshkey_dispatch")
        tags := cloud.InstanceTags{"arvados-ec2-driver": "test"}
+
+       defer func() {
+               instances, err := ap.Instances(tags)
+               c.Assert(err, check.IsNil)
+               for _, inst := range instances {
+                       c.Logf("cleanup: destroy instance %s", inst)
+                       c.Check(inst.Destroy(), check.IsNil)
+               }
+       }()
+
        inst1, err := ap.Create(cluster.InstanceTypes["tiny-preemptible"], img, tags, "true", pk)
        c.Assert(err, check.IsNil)
        defer inst1.Destroy()
@@ -305,13 +315,15 @@ func (*EC2InstanceSetSuite) TestInstancePriceHistory(c *check.C) {
                instances, err = ap.Instances(tags)
                running := 0
                for _, inst := range instances {
-                       if inst.Address() != "" {
+                       if *inst.(*ec2Instance).instance.InstanceLifecycle == "spot" {
                                running++
                        }
                }
                if running >= 2 {
+                       c.Logf("instances are running, and identifiable as spot instances")
                        break
                }
+               c.Logf("waiting for instances to be identifiable as spot instances...")
                time.Sleep(10 * time.Second)
        }