mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 17:11:30 +00:00
fix(e2e): drop catalog-download import path from phase4_Image
`spx admin images import --name ubuntu-26.04-x86_64` with wantErr=true
was meant to detect that bootstrap-install.sh already imported the AMI
and short-circuit on the duplicate exit code. After the v6 gold-image
bump preloaded `~/images/ubuntu-26.04.img` and bootstrap-install.sh
switched to `--file` for the import, two things broke at once:
- The catalog `--name` path no longer hits a duplicate guard for the
--file-imported AMI, so the import re-downloads ~857MB and either
succeeds (failing the wantErr=true assertion) or wedges the job
timeout while the catalog server crawls along at 16KB/s.
- `--file` from the test won't work either: the test binary runs as
`tf-user` over SSH, while bootstrap-install.sh placed the image at
`/home/spinifex/images/...` (mode 0700 home dir).
bootstrap-install.sh is already responsible for staging the AMI. The
test's job is verifying DescribeImages round-trips by-name and by-ID —
not re-exercising import. Trust the bootstrap-staged AMI and stop
calling import.
Keeps the 26.04→24.04 dual-detect for the v3 gold image transition;
drop the 24.04 candidate when no envs remain on v3.
Refs mulga-siv-115 (caught by the EC2 cold-boot fast-path E2E run on
feat/ec2-coldboot-fastpath).
This commit is contained in:
@@ -3,7 +3,6 @@
|
|||||||
package single
|
package single
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
@@ -12,102 +11,53 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
// amiIDRE matches "ami-<hex>" anywhere in spx import output. The CLI prints
|
// phase4_Image rediscovers the architecture-appropriate Ubuntu AMI that
|
||||||
// the new AMI ID on a "✅ Image import complete. Image-ID (AMI): ami-..."
|
// bootstrap-install.sh imported from the pre-staged gold-image file
|
||||||
// line; capturing the ID alone keeps us tolerant of the surrounding format
|
// (~/images/ubuntu-{26,24}.04.img → `spx admin images import --file`) and
|
||||||
// changing (the bash script uses a separate describe-images call entirely
|
// stashes the ID on the fixture for Phase 5+. Maps to run-e2e.sh ~233–255.
|
||||||
// because it didn't trust the CLI output).
|
|
||||||
var amiIDRE = regexp.MustCompile(`ami-[0-9a-f]+`)
|
|
||||||
|
|
||||||
// phase4_Image imports (or rediscovers) the architecture-appropriate Ubuntu
|
|
||||||
// AMI staged by bootstrap-install.sh and stashes the ID on the fixture for
|
|
||||||
// Phase 5+. Maps to run-e2e.sh ~233–255.
|
|
||||||
func phase4_Image(t *testing.T, fix *Fixture) {
|
func phase4_Image(t *testing.T, fix *Fixture) {
|
||||||
harness.Phase(t, "Phase 4 — Image Management")
|
harness.Phase(t, "Phase 4 — Image Management")
|
||||||
require.NotEmpty(t, fix.Arch, "Phase 2 must populate fix.Arch before Phase 4")
|
require.NotEmpty(t, fix.Arch, "Phase 2 must populate fix.Arch before Phase 4")
|
||||||
|
|
||||||
// Try the current catalog entry (26.04 / resolute) first, fall back to
|
// Bootstrap-install.sh has already imported the staged ubuntu cloud
|
||||||
// 24.04 (noble) for clusters still on the v3 gold image. Drop the
|
// image via `--file` (v6+ gold stages ubuntu-26.04, v3 stages
|
||||||
// fallback once 24.04 is gone from spinifex/utils/images.go.
|
// ubuntu-24.04). DescribeImages by canonical name is enough — running
|
||||||
|
// `spx admin images import --name` here triggers an 800MB+ catalog
|
||||||
|
// download that outlasts the job timeout, and `--file` would need a
|
||||||
|
// path readable by the test-binary user (different from the user
|
||||||
|
// bootstrap-install.sh ran as). Drop the 24.04 candidate once the v3
|
||||||
|
// gold image is fully retired.
|
||||||
candidates := []string{
|
candidates := []string{
|
||||||
"ubuntu-26.04-" + fix.Arch,
|
"ami-ubuntu-26.04-" + fix.Arch,
|
||||||
"ubuntu-24.04-" + fix.Arch,
|
"ami-ubuntu-24.04-" + fix.Arch,
|
||||||
}
|
}
|
||||||
var imgName, out string
|
var resolvedName, resolvedID string
|
||||||
for _, name := range candidates {
|
for _, name := range candidates {
|
||||||
harness.Detail(t, "image_candidate", name, "arch", fix.Arch)
|
harness.Detail(t, "image_candidate", name, "arch", fix.Arch)
|
||||||
harness.Step(t, "spx admin images import --name %s", name)
|
harness.Step(t, "describe-images filter name=%s", name)
|
||||||
// wantErr=true: bootstrap-install.sh has already imported the
|
out, err := fix.AWS.EC2.DescribeImages(&ec2.DescribeImagesInput{
|
||||||
// AMI in most environments, so the import returns non-zero on
|
|
||||||
// duplicate. We don't care about the exit code — we care about
|
|
||||||
// either parsing an AMI ID or successfully filtering
|
|
||||||
// DescribeImages by the canonical ami-<name> tag afterwards.
|
|
||||||
out = harness.SpxRun(t, true, "admin", "images", "import", "--name", name)
|
|
||||||
imgName = name
|
|
||||||
// If DescribeImages can find this name, stop trying further
|
|
||||||
// candidates — bootstrap staged this version.
|
|
||||||
probe, err := fix.AWS.EC2.DescribeImages(&ec2.DescribeImagesInput{
|
|
||||||
Filters: []*ec2.Filter{
|
Filters: []*ec2.Filter{
|
||||||
{Name: aws.String("name"), Values: []*string{aws.String("ami-" + name)}},
|
{Name: aws.String("name"), Values: []*string{aws.String(name)}},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err == nil && len(probe.Images) > 0 {
|
if err == nil && len(out.Images) > 0 {
|
||||||
|
resolvedName = name
|
||||||
|
resolvedID = aws.StringValue(out.Images[0].ImageId)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
harness.Detail(t, "image", imgName)
|
require.NotEmptyf(t, resolvedID,
|
||||||
|
"no Ubuntu AMI found via DescribeImages — bootstrap-install.sh did not stage one (tried: %v)", candidates)
|
||||||
// Try to parse the AMI ID directly out of the CLI's success line.
|
require.NotEmpty(t, resolvedName, "resolved name went empty")
|
||||||
amiID := amiIDRE.FindString(out)
|
harness.Detail(t, "image", resolvedName, "ami", resolvedID)
|
||||||
if amiID != "" {
|
|
||||||
harness.Detail(t, "spx_parsed_ami", amiID)
|
|
||||||
} else {
|
|
||||||
harness.Step(t, "spx import did not yield AMI ID; falling back to describe-images")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Either confirm the parsed ID or look it up by name.
|
|
||||||
// Bash filters on `Name=name,Values=ami-${IMAGE_NAME}` — the leading
|
|
||||||
// `ami-` prefix is part of the AMI's *name* in spinifex (admin.go:487),
|
|
||||||
// not the AMI ID. Replicate exactly.
|
|
||||||
filterName := "ami-" + imgName
|
|
||||||
describeOut, err := fix.AWS.EC2.DescribeImages(&ec2.DescribeImagesInput{
|
|
||||||
Filters: []*ec2.Filter{
|
|
||||||
{Name: aws.String("name"), Values: []*string{aws.String(filterName)}},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
require.NoErrorf(t, err, "describe-images filter name=%s", filterName)
|
|
||||||
require.NotEmptyf(t, describeOut.Images,
|
|
||||||
"no AMI matched name=%s — bootstrap-install.sh did not stage it and the import failed:\n%s",
|
|
||||||
filterName, truncate(out, 2000))
|
|
||||||
|
|
||||||
resolvedID := aws.StringValue(describeOut.Images[0].ImageId)
|
|
||||||
require.NotEmpty(t, resolvedID, "describe-images returned blank ImageId")
|
|
||||||
|
|
||||||
if amiID != "" && amiID != resolvedID {
|
|
||||||
// Parsed an AMI ID from spx output but it doesn't match what
|
|
||||||
// describe-images by name returns — surface the mismatch loudly
|
|
||||||
// rather than silently preferring one source over the other.
|
|
||||||
t.Fatalf("spx output AMI %s != describe-images AMI %s for name %s",
|
|
||||||
amiID, resolvedID, filterName)
|
|
||||||
}
|
|
||||||
fix.AMIID = resolvedID
|
fix.AMIID = resolvedID
|
||||||
|
|
||||||
harness.Step(t, "describe-images by AMI ID (verify exactly one match)")
|
harness.Step(t, "describe-images by AMI ID (verify round-trip)")
|
||||||
byID, err := fix.AWS.EC2.DescribeImages(&ec2.DescribeImagesInput{
|
byID, err := fix.AWS.EC2.DescribeImages(&ec2.DescribeImagesInput{
|
||||||
ImageIds: []*string{aws.String(fix.AMIID)},
|
ImageIds: []*string{aws.String(fix.AMIID)},
|
||||||
})
|
})
|
||||||
require.NoErrorf(t, err, "describe-images %s", fix.AMIID)
|
require.NoErrorf(t, err, "describe-images %s", fix.AMIID)
|
||||||
require.Lenf(t, byID.Images, 1, "expected exactly 1 image for %s, got %d", fix.AMIID, len(byID.Images))
|
require.Lenf(t, byID.Images, 1, "expected exactly 1 image for %s, got %d", fix.AMIID, len(byID.Images))
|
||||||
require.Equal(t, fix.AMIID, aws.StringValue(byID.Images[0].ImageId), "round-trip AMI ID mismatch")
|
require.Equal(t, fix.AMIID, aws.StringValue(byID.Images[0].ImageId), "round-trip AMI ID mismatch")
|
||||||
|
require.Equal(t, resolvedName, aws.StringValue(byID.Images[0].Name), "lookup-by-ID returned a different Name than lookup-by-Name")
|
||||||
harness.Detail(t, "ami", fix.AMIID, "name", aws.StringValue(byID.Images[0].Name))
|
|
||||||
}
|
|
||||||
|
|
||||||
// truncate is used to keep failure messages from dumping arbitrarily large
|
|
||||||
// spx CLI output verbatim into the test log.
|
|
||||||
func truncate(s string, n int) string {
|
|
||||||
if len(s) <= n {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return s[:n] + "...[truncated]"
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user