Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Work with instances not in ASG #7

Merged
merged 1 commit into from
Dec 11, 2023
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
13 changes: 11 additions & 2 deletions internal/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,12 +246,21 @@ func (c *Controller) KillInstance(ctx context.Context, instanceID string) (err e
ShouldDecrementDesiredCapacity: aws.Bool(true),
})

if err != nil {
// A special instance of the error is when the instance is not part of
// the autoscaling group. This can happen when the instance successfully
// detached but for some reason the termination request failed.
//
// This will fix one-off errors and machines manually connected to the
// worker pool (as long as they terminate upon request), but if there
// are multiple ASGs connected to the same worker pool, this will be a
// common occurrence and will break the entire autoscaling logic.
if err != nil && !strings.Contains(err.Error(), "is not part of Auto Scaling group") {
err = fmt.Errorf("could not detach instance from autoscaling group: %v", err)
return err
}

// Now that the instance is detached from the ASG, we can terminate it.
// Now that the instance is detached from the ASG (or was never part of
// the ASG), we can terminate it.
_, err = c.EC2.TerminateInstances(ctx, &ec2.TerminateInstancesInput{
InstanceIds: []string{instanceID},
})
Expand Down
37 changes: 25 additions & 12 deletions internal/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -440,13 +440,11 @@ func TestController(t *testing.T) {
})
})

g.Describe("when the detach call succeeds", func() {
g.Describe("when the detach call does not fail", func() {
var terminateCall *mock.Call
var terminateInput *ec2.TerminateInstancesInput

g.BeforeEach(func() {
detachCall.Return(nil, nil)

terminateInput = nil

terminateCall = mockEC2.On(
Expand All @@ -460,23 +458,38 @@ func TestController(t *testing.T) {
)
})

g.Describe("when the terminate call fails", func() {
g.BeforeEach(func() { terminateCall.Return(nil, errors.New("bacon")) })

g.It("send the correct input", func() {
Expect(terminateInput).NotTo(BeNil())
Expect(terminateInput.InstanceIds).To(ConsistOf(instanceID))
g.Describe("when the instance is not part of the ASG", func() {
g.BeforeEach(func() {
detachCall.Return(nil, errors.New("instance is not part of Auto Scaling group"))
terminateCall.Return(nil, errors.New("bacon"))
})

g.It("should return an error", func() {
Expect(err).To(MatchError("could not terminate detached instance: bacon"))
})
})

g.Describe("when the terminate call succeeds", func() {
g.BeforeEach(func() { terminateCall.Return(nil, nil) })
g.Describe("when the detach call succeeds", func() {
g.BeforeEach(func() { detachCall.Return(nil, nil) })

g.Describe("when the terminate call fails", func() {
g.BeforeEach(func() { terminateCall.Return(nil, errors.New("bacon")) })

g.It("send the correct input", func() {
Expect(terminateInput).NotTo(BeNil())
Expect(terminateInput.InstanceIds).To(ConsistOf(instanceID))
})

g.It("succeeds", func() { Expect(err).NotTo(HaveOccurred()) })
g.It("should return an error", func() {
Expect(err).To(MatchError("could not terminate detached instance: bacon"))
})
})

g.Describe("when the terminate call succeeds", func() {
g.BeforeEach(func() { terminateCall.Return(nil, nil) })

g.It("succeeds", func() { Expect(err).NotTo(HaveOccurred()) })
})
})
})
})
Expand Down
Loading