fix: ModifyInstanceAttribute SourceDestCheck

This commit is contained in:
Julian Sommer
2026-03-31 10:30:14 +10:00
parent a7925d65f2
commit 4f3b54abc2
4 changed files with 70 additions and 0 deletions
@@ -1168,6 +1168,18 @@ func (d *Daemon) handleEC2ModifyInstanceAttribute(msg *nats.Msg) {
instanceID := *input.InstanceId
// SourceDestCheck is a networking concept that doesn't apply to bare-metal VMs.
// Accept the call as a no-op so Terraform and the AWS CLI don't error out.
// Unlike InstanceType/UserData, AWS allows this on running instances, so handle
// it before the stopped-state gate.
if input.SourceDestCheck != nil {
slog.Info("handleEC2ModifyInstanceAttribute: accepting SourceDestCheck (no-op on bare metal)", "instanceId", instanceID)
if err := msg.Respond([]byte(`{}`)); err != nil {
slog.Error("Failed to respond to NATS request", "err", err)
}
return
}
if d.jsManager == nil {
slog.Error("handleEC2ModifyInstanceAttribute: JetStream not available")
respondWithError(msg, awserrors.ErrorServerInternal)
+21
View File
@@ -1736,6 +1736,27 @@ func TestHandleEC2ModifyInstanceAttribute_ChangeUserData(t *testing.T) {
assert.Equal(t, "IyEvYmluL2Jhc2g=", *updated.RunInstancesInput.UserData)
}
func TestHandleEC2ModifyInstanceAttribute_SourceDestCheck(t *testing.T) {
natsURL := sharedJSNATSURL
daemon := createFullTestDaemonWithJetStream(t, natsURL)
sub, err := daemon.natsConn.QueueSubscribe("ec2.ModifyInstanceAttribute", "spinifex-workers", daemon.handleEC2ModifyInstanceAttribute)
require.NoError(t, err)
defer sub.Unsubscribe()
// SourceDestCheck is a no-op that succeeds without requiring a stopped instance
// in KV — Terraform sends this on running instances right after creation.
input := &ec2.ModifyInstanceAttributeInput{
InstanceId: aws.String("i-modify-sdc-001"),
SourceDestCheck: &ec2.AttributeBooleanValue{Value: aws.Bool(false)},
}
reqData, _ := json.Marshal(input)
reply, err := natsRequest(daemon.natsConn, "ec2.ModifyInstanceAttribute", reqData, 5*time.Second)
require.NoError(t, err)
assert.Equal(t, `{}`, string(reply.Data))
}
func TestHandleEC2ModifyInstanceAttribute_InstanceNotFound(t *testing.T) {
natsURL := sharedJSNATSURL
@@ -35,6 +35,9 @@ func ValidateModifyInstanceAttributeInput(input *ec2.ModifyInstanceAttributeInpu
if input.UserData != nil {
count++
}
if input.SourceDestCheck != nil {
count++
}
if count != 1 {
return errors.New(awserrors.ErrorInvalidParameterValue)
}
@@ -95,6 +95,24 @@ func TestValidateModifyInstanceAttributeInput_ValidUserData(t *testing.T) {
assert.NoError(t, err)
}
func TestValidateModifyInstanceAttributeInput_ValidSourceDestCheck(t *testing.T) {
err := ValidateModifyInstanceAttributeInput(&ec2.ModifyInstanceAttributeInput{
InstanceId: aws.String("i-abc123"),
SourceDestCheck: &ec2.AttributeBooleanValue{Value: aws.Bool(true)},
})
assert.NoError(t, err)
}
func TestValidateModifyInstanceAttributeInput_SourceDestCheckWithOtherAttribute(t *testing.T) {
err := ValidateModifyInstanceAttributeInput(&ec2.ModifyInstanceAttributeInput{
InstanceId: aws.String("i-abc123"),
SourceDestCheck: &ec2.AttributeBooleanValue{Value: aws.Bool(false)},
InstanceType: &ec2.AttributeValue{Value: aws.String("t3.micro")},
})
require.Error(t, err)
assert.Equal(t, awserrors.ErrorInvalidParameterValue, err.Error())
}
// --- Gateway function tests ---
func TestModifyInstanceAttribute_Success(t *testing.T) {
@@ -117,6 +135,22 @@ func TestModifyInstanceAttribute_Success(t *testing.T) {
assert.NoError(t, err)
}
func TestModifyInstanceAttribute_SourceDestCheck(t *testing.T) {
_, nc := startTestNATSServer(t)
nc.QueueSubscribe("ec2.ModifyInstanceAttribute", "spinifex-workers", func(msg *nats.Msg) {
msg.Respond([]byte(`{}`))
})
input := &ec2.ModifyInstanceAttributeInput{
InstanceId: aws.String("i-test123"),
SourceDestCheck: &ec2.AttributeBooleanValue{Value: aws.Bool(true)},
}
_, err := ModifyInstanceAttribute(input, nc, "123456789012")
assert.NoError(t, err)
}
func TestModifyInstanceAttribute_DaemonError(t *testing.T) {
_, nc := startTestNATSServer(t)