mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 17:11:30 +00:00
fix: omit the user data attribute value when an instance has none (#1097)
DescribeInstanceAttribute always returned a Value for userData, an empty string when the instance was launched without any. AWS returns the attribute with no Value at all in that case. The Terraform provider reads user_data only when Value is non-nil, so an empty string made it record the hash of the empty string in state and propose a change on every plan for an instance whose configuration names no user data.
This commit is contained in:
@@ -3092,12 +3092,12 @@ func (s *InstanceServiceImpl) DescribeInstanceAttribute(ctx context.Context, inp
|
||||
|
||||
case ec2.InstanceAttributeNameUserData:
|
||||
// AWS returns user-data base64-encoded; RunInstancesInput.UserData is the
|
||||
// canonical base64 store, set at launch and kept in sync by Modify.
|
||||
var val string
|
||||
if instance.RunInstancesInput != nil && instance.RunInstancesInput.UserData != nil {
|
||||
val = *instance.RunInstancesInput.UserData
|
||||
// canonical base64 store, set at launch and kept in sync by Modify. An
|
||||
// instance with no user data carries no Value at all, not an empty one.
|
||||
output.UserData = &ec2.AttributeValue{}
|
||||
if instance.RunInstancesInput != nil && aws.StringValue(instance.RunInstancesInput.UserData) != "" {
|
||||
output.UserData.Value = aws.String(*instance.RunInstancesInput.UserData)
|
||||
}
|
||||
output.UserData = &ec2.AttributeValue{Value: &val}
|
||||
|
||||
case ec2.InstanceAttributeNameDisableApiTermination:
|
||||
// Read under the manager lock so we serialise with a concurrent
|
||||
|
||||
@@ -4822,3 +4822,35 @@ func TestPrepareRunInstances_PreCreatedENIAttachErrorSurfaced(t *testing.T) {
|
||||
assert.Equal(t, 1, eni.attachCalls)
|
||||
assert.Equal(t, 0, eni.createCalls)
|
||||
}
|
||||
|
||||
// TestDescribeInstanceAttribute_UserDataUnsetCarriesNoValue pins the shape AWS
|
||||
// returns for an instance launched without user data: the attribute is present
|
||||
// and its Value is absent. The Terraform provider reads user_data only when
|
||||
// Value is non-nil, so an empty string makes it record the hash of "" and
|
||||
// propose a change on every plan.
|
||||
func TestDescribeInstanceAttribute_UserDataUnsetCarriesNoValue(t *testing.T) {
|
||||
const id = "i-userdata-unset"
|
||||
const owner = "000000000000"
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
input *ec2.RunInstancesInput
|
||||
}{
|
||||
{name: "no RunInstancesInput", input: nil},
|
||||
{name: "nil UserData", input: &ec2.RunInstancesInput{}},
|
||||
{name: "empty UserData", input: &ec2.RunInstancesInput{UserData: aws.String("")}},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
v := &vm.VM{ID: id, AccountID: owner, RunInstancesInput: tc.input}
|
||||
svc := &InstanceServiceImpl{vmMgr: mgrWith(map[string]*vm.VM{id: v})}
|
||||
|
||||
out, err := svc.DescribeInstanceAttribute(context.Background(), &ec2.DescribeInstanceAttributeInput{
|
||||
InstanceId: aws.String(id),
|
||||
Attribute: aws.String(ec2.InstanceAttributeNameUserData),
|
||||
}, owner)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, out.UserData, "AWS returns the attribute itself even when it holds nothing")
|
||||
assert.Nil(t, out.UserData.Value, "an instance with no user data carries no Value, not an empty one")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user