Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
## UNRELEASED

BUG FIXES:
* plugin/target/aws-asg: Ignore warm pool activities when determining ASG readiness [[GH-1151]](https://github.com/hashicorp/nomad-autoscaler/pull/1151)

## 0.4.8 (November 13, 2025)

IMPROVEMENTS:
Expand Down
16 changes: 16 additions & 0 deletions plugins/builtin/target/aws-asg/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"context"
"fmt"
"strconv"
"strings"

"github.com/aws/aws-sdk-go-v2/service/autoscaling"
"github.com/aws/aws-sdk-go-v2/service/autoscaling/types"
Expand Down Expand Up @@ -270,9 +271,24 @@ func (t *TargetPlugin) calculateDirection(asgDesired, strategyDesired int64) (in
return 0, ""
}

func warmPoolActivity(activity types.Activity) bool {
if activity.Description == nil {
return false
}

desc := *activity.Description
return strings.Contains(desc, "Launching a new EC2 instance into warm pool:") ||
strings.Contains(desc, "Terminating EC2 instance from warm pool:")
}

// processLastActivity updates the status object based on the details within
// the last scaling activity.
func processLastActivity(activity types.Activity, status *sdk.TargetStatus) {
// Warm pool activities are not considered scaling activities in the context of
// scaling the asg in or out, so we skip them.
if warmPoolActivity(activity) {
return
}

// If the last activities progress is not nil then check whether this
// finished or not. In the event there is a current activity in progress
Expand Down
85 changes: 85 additions & 0 deletions plugins/builtin/target/aws-asg/plugin/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,57 @@ func TestTargetPlugin_calculateDirection(t *testing.T) {
}
}

func Test_warmPoolActivity(t *testing.T) {
testCases := []struct {
inputActivity types.Activity
expectedResponse bool
name string
}{
{
inputActivity: types.Activity{
Description: ptr.Of("Launching a new EC2 instance into warm pool: i-0b22a22eec53b9321"),
},
expectedResponse: true,
name: "instance launched into warm pool",
},
{
inputActivity: types.Activity{
Description: ptr.Of("Terminating EC2 instance from warm pool: i-0b22a22eec53b9321"),
},
expectedResponse: true,
name: "instance terminated from warm pool",
},
{
inputActivity: types.Activity{
Description: ptr.Of("Launching a new EC2 instance from warm pool: i-0b22a22eec53b9321"),
},
expectedResponse: false,
name: "instance launched into ASG from warm pool",
},
{
inputActivity: types.Activity{
Description: nil,
},
expectedResponse: false,
name: "nil description",
},
{
inputActivity: types.Activity{
Description: ptr.Of(""),
},
expectedResponse: false,
name: "empty description",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
res := warmPoolActivity(tc.inputActivity)
assert.Equal(t, tc.expectedResponse, res, tc.name)
})
}
}

func Test_processLastActivity(t *testing.T) {

testTime := time.Date(2020, time.April, 13, 8, 4, 0, 0, time.UTC)
Expand Down Expand Up @@ -114,6 +165,40 @@ func Test_processLastActivity(t *testing.T) {
},
name: "latest activity all nils",
},
{
inputActivity: types.Activity{
Progress: ptr.Of(int32(75)),
Description: ptr.Of("Launching a new EC2 instance into warm pool:"),
},
inputStatus: &sdk.TargetStatus{
Ready: true,
Count: 1,
Meta: map[string]string{},
},
expectedStatus: &sdk.TargetStatus{
Ready: true,
Count: 1,
Meta: map[string]string{},
},
name: "latest activity was instance launched into warm pool",
},
{
inputActivity: types.Activity{
Progress: ptr.Of(int32(75)),
Description: ptr.Of("Terminating EC2 instance from warm pool:"),
},
inputStatus: &sdk.TargetStatus{
Ready: true,
Count: 1,
Meta: map[string]string{},
},
expectedStatus: &sdk.TargetStatus{
Ready: true,
Count: 1,
Meta: map[string]string{},
},
name: "latest activity was instance terminated from warm pool",
},
}

for _, tc := range testCases {
Expand Down
Loading