mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 17:11:30 +00:00
207 lines
9.4 KiB
Go
207 lines
9.4 KiB
Go
//go:build e2e
|
|
|
|
package single
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
"github.com/aws/aws-sdk-go/service/ec2"
|
|
"github.com/mulgadc/spinifex/tests/e2e/harness"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// runLaunchTemplates drives the launch-template control plane through the
|
|
// deployed AWS gateway, then launches an instance from the selected default
|
|
// version. It intentionally uses parentheses in the name: they are valid AWS
|
|
// launch-template characters but require the service's KV name-index encoding.
|
|
func runLaunchTemplates(t *testing.T, fix *Fixture) {
|
|
harness.Phase(t, "Single — EC2 Launch Templates")
|
|
|
|
amiID := needAMI(t, fix)
|
|
instanceType, _ := needInstanceTypeArch(t, fix)
|
|
keyName, _ := needKeyPair(t, fix)
|
|
templateName := fmt.Sprintf("e2e-lt-(%s)", fix.Harness.Scratch())
|
|
|
|
// e2e:allow-create — the launch template lifecycle is the subject under test.
|
|
createOut, err := fix.AWS.EC2.CreateLaunchTemplate(&ec2.CreateLaunchTemplateInput{
|
|
LaunchTemplateName: aws.String(templateName),
|
|
VersionDescription: aws.String("initial version"),
|
|
LaunchTemplateData: &ec2.RequestLaunchTemplateData{
|
|
ImageId: aws.String(amiID),
|
|
InstanceType: aws.String(instanceType),
|
|
KeyName: aws.String(keyName),
|
|
},
|
|
TagSpecifications: []*ec2.TagSpecification{{
|
|
ResourceType: aws.String("launch-template"),
|
|
Tags: []*ec2.Tag{
|
|
{Key: aws.String("e2e-suite"), Value: aws.String(fix.Harness.Scratch())},
|
|
},
|
|
}},
|
|
})
|
|
require.NoError(t, err, "create-launch-template")
|
|
require.NotNil(t, createOut.LaunchTemplate, "create-launch-template returned no template")
|
|
templateID := aws.StringValue(createOut.LaunchTemplate.LaunchTemplateId)
|
|
require.NotEmpty(t, templateID, "create-launch-template returned an empty id")
|
|
assert.Equal(t, int64(1), aws.Int64Value(createOut.LaunchTemplate.DefaultVersionNumber))
|
|
|
|
templateDeleted := false
|
|
t.Cleanup(func() {
|
|
if templateDeleted {
|
|
return
|
|
}
|
|
if _, err := fix.AWS.EC2.DeleteLaunchTemplate(&ec2.DeleteLaunchTemplateInput{
|
|
LaunchTemplateName: aws.String(templateName),
|
|
}); err != nil {
|
|
t.Logf("cleanup delete-launch-template %q: %v", templateName, err)
|
|
}
|
|
})
|
|
|
|
harness.Step(t, "describe-launch-templates by launch-template tag")
|
|
descTemplates, err := fix.AWS.EC2.DescribeLaunchTemplates(&ec2.DescribeLaunchTemplatesInput{
|
|
Filters: []*ec2.Filter{{
|
|
Name: aws.String("tag:e2e-suite"),
|
|
Values: []*string{aws.String(fix.Harness.Scratch())},
|
|
}},
|
|
})
|
|
require.NoError(t, err, "describe-launch-templates by tag")
|
|
require.Len(t, descTemplates.LaunchTemplates, 1)
|
|
assert.Equal(t, templateID, aws.StringValue(descTemplates.LaunchTemplates[0].LaunchTemplateId))
|
|
|
|
// SourceVersion inherits the AMI and instance type from v1 while the
|
|
// non-nil UserData field replaces only that whole field.
|
|
const userData = "ZWNobyBsYXVuY2gtdGVtcGxhdGUK"
|
|
// e2e:allow-create — version creation is part of the launch-template lifecycle under test.
|
|
v2Out, err := fix.AWS.EC2.CreateLaunchTemplateVersion(&ec2.CreateLaunchTemplateVersionInput{
|
|
LaunchTemplateName: aws.String(templateName),
|
|
SourceVersion: aws.String("1"),
|
|
VersionDescription: aws.String("source merge version"),
|
|
LaunchTemplateData: &ec2.RequestLaunchTemplateData{
|
|
UserData: aws.String(userData),
|
|
},
|
|
})
|
|
require.NoError(t, err, "create-launch-template-version from source")
|
|
require.NotNil(t, v2Out.LaunchTemplateVersion, "create-launch-template-version returned no version")
|
|
v2 := v2Out.LaunchTemplateVersion
|
|
assert.Equal(t, int64(2), aws.Int64Value(v2.VersionNumber))
|
|
require.NotNil(t, v2.LaunchTemplateData)
|
|
assert.Equal(t, amiID, aws.StringValue(v2.LaunchTemplateData.ImageId))
|
|
assert.Equal(t, instanceType, aws.StringValue(v2.LaunchTemplateData.InstanceType))
|
|
assert.Equal(t, userData, aws.StringValue(v2.LaunchTemplateData.UserData))
|
|
|
|
harness.Step(t, "describe-launch-template-versions $Latest by name")
|
|
latestOut, err := fix.AWS.EC2.DescribeLaunchTemplateVersions(&ec2.DescribeLaunchTemplateVersionsInput{
|
|
LaunchTemplateName: aws.String(templateName),
|
|
Versions: []*string{aws.String("$Latest")},
|
|
})
|
|
require.NoError(t, err, "describe-launch-template-versions $Latest")
|
|
require.Len(t, latestOut.LaunchTemplateVersions, 1)
|
|
assert.Equal(t, int64(2), aws.Int64Value(latestOut.LaunchTemplateVersions[0].VersionNumber))
|
|
|
|
harness.Step(t, "modify-launch-template default version -> 2")
|
|
modifyOut, err := fix.AWS.EC2.ModifyLaunchTemplate(&ec2.ModifyLaunchTemplateInput{
|
|
LaunchTemplateId: aws.String(templateID),
|
|
DefaultVersion: aws.String("2"),
|
|
})
|
|
require.NoError(t, err, "modify-launch-template")
|
|
require.NotNil(t, modifyOut.LaunchTemplate)
|
|
assert.Equal(t, int64(2), aws.Int64Value(modifyOut.LaunchTemplate.DefaultVersionNumber))
|
|
|
|
// Create and remove a tail version so DeleteLaunchTemplateVersions and
|
|
// $Latest-after-delete are covered without disturbing the default v2. This
|
|
// version also drives a nested timestamp through the EC2 query parser.
|
|
validUntil := time.Date(2030, time.January, 2, 3, 4, 5, 0, time.UTC)
|
|
// e2e:allow-create — version creation is part of the launch-template lifecycle under test.
|
|
v3Out, err := fix.AWS.EC2.CreateLaunchTemplateVersion(&ec2.CreateLaunchTemplateVersionInput{
|
|
LaunchTemplateId: aws.String(templateID),
|
|
LaunchTemplateData: &ec2.RequestLaunchTemplateData{
|
|
InstanceType: aws.String(instanceType),
|
|
InstanceMarketOptions: &ec2.LaunchTemplateInstanceMarketOptionsRequest{
|
|
MarketType: aws.String("spot"),
|
|
SpotOptions: &ec2.LaunchTemplateSpotMarketOptionsRequest{
|
|
ValidUntil: aws.Time(validUntil),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
require.NoError(t, err, "create-launch-template-version tail")
|
|
require.NotNil(t, v3Out.LaunchTemplateVersion)
|
|
assert.Equal(t, int64(3), aws.Int64Value(v3Out.LaunchTemplateVersion.VersionNumber))
|
|
|
|
latestOut, err = fix.AWS.EC2.DescribeLaunchTemplateVersions(&ec2.DescribeLaunchTemplateVersionsInput{
|
|
LaunchTemplateId: aws.String(templateID),
|
|
Versions: []*string{aws.String("$Latest")},
|
|
})
|
|
require.NoError(t, err, "describe-launch-template-versions $Latest tail")
|
|
require.Len(t, latestOut.LaunchTemplateVersions, 1)
|
|
require.NotNil(t, latestOut.LaunchTemplateVersions[0].LaunchTemplateData)
|
|
require.NotNil(t, latestOut.LaunchTemplateVersions[0].LaunchTemplateData.InstanceMarketOptions)
|
|
require.NotNil(t, latestOut.LaunchTemplateVersions[0].LaunchTemplateData.InstanceMarketOptions.SpotOptions)
|
|
require.NotNil(t, latestOut.LaunchTemplateVersions[0].LaunchTemplateData.InstanceMarketOptions.SpotOptions.ValidUntil)
|
|
assert.Equal(t, validUntil, *latestOut.LaunchTemplateVersions[0].LaunchTemplateData.InstanceMarketOptions.SpotOptions.ValidUntil)
|
|
|
|
deleteVersionsOut, err := fix.AWS.EC2.DeleteLaunchTemplateVersions(&ec2.DeleteLaunchTemplateVersionsInput{
|
|
LaunchTemplateId: aws.String(templateID),
|
|
Versions: []*string{aws.String("3")},
|
|
})
|
|
require.NoError(t, err, "delete-launch-template-versions")
|
|
require.Len(t, deleteVersionsOut.SuccessfullyDeletedLaunchTemplateVersions, 1)
|
|
assert.Equal(t, int64(3), aws.Int64Value(deleteVersionsOut.SuccessfullyDeletedLaunchTemplateVersions[0].VersionNumber))
|
|
assert.Empty(t, deleteVersionsOut.UnsuccessfullyDeletedLaunchTemplateVersions)
|
|
|
|
latestOut, err = fix.AWS.EC2.DescribeLaunchTemplateVersions(&ec2.DescribeLaunchTemplateVersionsInput{
|
|
LaunchTemplateId: aws.String(templateID),
|
|
Versions: []*string{aws.String("$Latest")},
|
|
})
|
|
require.NoError(t, err, "describe-launch-template-versions $Latest after delete")
|
|
require.Len(t, latestOut.LaunchTemplateVersions, 1)
|
|
assert.Equal(t, int64(2), aws.Int64Value(latestOut.LaunchTemplateVersions[0].VersionNumber))
|
|
|
|
vpc := harness.EnsureDefaultVPC(t, fix.Harness)
|
|
require.NotEmpty(t, vpc.SubnetID)
|
|
require.NotEmpty(t, vpc.SGID)
|
|
|
|
harness.Step(t, "run-instances from default launch-template version")
|
|
// e2e:allow-create — the instance verifies launch-template expansion in the real launch path.
|
|
runOut, err := fix.AWS.EC2.RunInstances(&ec2.RunInstancesInput{
|
|
LaunchTemplate: &ec2.LaunchTemplateSpecification{LaunchTemplateId: aws.String(templateID)},
|
|
MinCount: aws.Int64(1),
|
|
MaxCount: aws.Int64(1),
|
|
SubnetId: aws.String(vpc.SubnetID),
|
|
SecurityGroupIds: []*string{
|
|
aws.String(vpc.SGID),
|
|
},
|
|
})
|
|
require.NoError(t, err, "run-instances with launch template")
|
|
require.NotEmpty(t, runOut.Instances, "run-instances returned no instances")
|
|
instanceID := aws.StringValue(runOut.Instances[0].InstanceId)
|
|
require.NotEmpty(t, instanceID, "run-instances returned an empty instance id")
|
|
t.Cleanup(func() {
|
|
_, _ = fix.AWS.EC2.TerminateInstances(&ec2.TerminateInstancesInput{
|
|
InstanceIds: []*string{aws.String(instanceID)},
|
|
})
|
|
})
|
|
|
|
instance := harness.WaitForInstanceState(t, fix.AWS, instanceID, "running")
|
|
assert.Equal(t, amiID, aws.StringValue(instance.ImageId), "templated AMI")
|
|
assert.Equal(t, instanceType, aws.StringValue(instance.InstanceType), "templated instance type")
|
|
|
|
_, err = fix.AWS.EC2.TerminateInstances(&ec2.TerminateInstancesInput{
|
|
InstanceIds: []*string{aws.String(instanceID)},
|
|
})
|
|
require.NoError(t, err, "terminate launch-template instance")
|
|
harness.WaitForInstanceState(t, fix.AWS, instanceID, "terminated")
|
|
|
|
harness.Step(t, "delete-launch-template by name")
|
|
deleteOut, err := fix.AWS.EC2.DeleteLaunchTemplate(&ec2.DeleteLaunchTemplateInput{
|
|
LaunchTemplateName: aws.String(templateName),
|
|
})
|
|
require.NoError(t, err, "delete-launch-template")
|
|
require.NotNil(t, deleteOut.LaunchTemplate)
|
|
assert.Equal(t, templateID, aws.StringValue(deleteOut.LaunchTemplate.LaunchTemplateId))
|
|
templateDeleted = true
|
|
}
|