uyuni-project/sumaform (github.com/uyuni-project/sumaform, 79 stars, pinned by commit not tag), module.server slice of its AWS backend
Source: https://github.com/uyuni-project/sumaform.git at c8a590801d0c7f60d9667f03391455a897900078.
Set: core. Lane: opentofu-native.
Why it is in the core set: a real project built for OpenTofu specifically, so OpenTofu-only surface is exercised
Clear. Every headline stage passes.
| Stage | Verdict | Duration | Detail |
|---|---|---|---|
| Cold deploy | pass | 1m13s | 11 managed resource instances, genuinely cold, genuinely unmarked |
| Migrate | pass | 3m12s | 7 stamped, 2 recorded (markers = record honoured at migrate time, GitHub issue #365 slice 2), 0 failed, 2 skipped |
| Replan from nothing | pass | 12s | Items 4, 5 and 6 (this script’s header) are all FIXED and the plan is genuinely empty (“No changes. Your infrastructure matches the configuration.”): live-import honours markers = record (located records for aws_instance.instance[0] and aws_ebs_volume.data_disk[0], confirmed at the store and by value against the AWS CLI both right after migrate and again after this empty replan), residue now covers NestingList/NestingSet/NestingMap blocks (internal/live/projection’s residueEligibleBlock, widened from the block’s SHAPE - whether carriesNoInformation can tell its absence from a real empty answer - never from a type name), and lex00/floci#103 (published in ghcr.io/lex00/floci@sha256:e16d9007a03093b6a6edd22273dee9d8253131f18581b0fa20ae6d34178a3079) now honours RunInstances’ BlockDeviceMapping.Ebs.VolumeSize for the root device, closing the one line (root_block_device.volume_size = 8 -> 200) that was this crossing’s own last wall. Plan moved 3 to add/0/0 (the original ABSENT gap) -> 2 to add/0/2 to destroy (item 4 fixed, item 5’s replacement exposed) -> 0 to add/1 to change/0 to destroy (item 5 fixed) -> empty (item 6 fixed by the emulator). |
| No-op apply | pass | 11s | genuine no-op: 7 tagged objects before, 7 after, no state file either time; module.server’s record-based instance and volume identities unchanged |
| Drift and reconverge | pass | 21s | the crossing VPC’s Name tag tampered out of band, plan proposed fixing exactly aws_vpc.crossing, apply changed 1 and reconverged the tag to sumaform-crossing-vpc; module.server’s record-based identities unaffected |
| Rename | pass | 41s | moved block: aws_eip.crossing_nat renamed with zero churn (0 add, 1 change, 0 destroy), marker rewritten in place; live-mv: aws_route_table.crossing_public renamed with zero churn, marker rewritten in place; stock oracle over the same two-object rename on cold_deploy’s own state also shows zero churn (0 add, 0 change, 0 destroy); both live ids unchanged, read via the AWS CLI |
| Remove a block | pass | 23s | choudoufu: deleting module.server’s block proposed exactly three destroys (0 add, 0 change, 3 destroy: the record-based instance and EBS volume, plus the untaggable/derived volume attachment), applied cleanly (0 added, 0 changed, 3 destroyed), the instance and volume are genuinely gone from the live account (instance State=terminated, volume absent, read via the AWS CLI, not choudoufu’s own report), and the next plan proposes no resource action; stock oracle on cold_deploy’s own state (E-ORACLE) also proposes the same three destroys |
| Change count | pass | 2m8s | Scaled aws_security_group.count_test, a self-contained 2-instance count block in its own count_test.tf at an address nothing else in this crossing names. SYNTHETIC, and NOT because this estate has no scalable knob: sumaform declares a real one (var.quantity, “number of hosts like this one”, driving count = var.quantity on aws_instance.instance), but every resource that knob scales is off the tag rung here - the instance and the EBS volume are markers = record by this crossing’s own strict block, aws_volume_attachment is untaggable, and all three carry sumaform’s own lifecycle { ignore_changes = [tags] } - so none of them can witness the stage’s identity clause off the live object. G4 exercises the real knob for the half it can settle: quantity 1 -> 2 through choudoufu proposes exactly 3 creates, all at index [1] (instance, data disk, volume attachment), index [0] untouched, identical to stock’s own plan for the same change on cold_deploy’s state (G-ORACLE-QUANTITY), and the estate plans empty again once it is restored; the down direction is NOT exercised on that knob (cold_deploy’s state is quantity=1, so there is no 2-instance stock state to scale down from). On the taggable block: scaling 2 -> 1 destroyed exactly count_test[1] (0 add, 0 change, 1 destroy) and left count_test[0]’s live GroupId sg-c33144b5b46badd79 AND its tofu-address marker aws_security_group.count_test:0 unchanged, both read through the AWS CLI rather than choudoufu’s report; count_test[1] (sg-78594594ab52897ff) verified absent by describe-security-groups length 0 in between; scaling 1 -> 2 created exactly count_test[1] (1 add, 0 change, 0 destroy) back under a NEW GroupId sg-b78fda4375c9444b2 carrying tofu-address=aws_security_group.count_test:1, with count_test[0] untouched throughout; the next plan is empty. Stock oracle (G-ORACLE): the identical 2-instance block stood up FOR REAL in its own idle floci account on FLOCI_PORT+3 - stock never had this block, so cold_deploy’s state could not be reused the way day2_remove’s and day2_replace’s oracles reuse it - shows the identical shape both directions, destroy the higher index only (sg-3910752a79c8bc9db gone, sg-cbd63512c1f716888 unchanged) and create the higher index back under a new id (sg-13a87d3119604564e). A new GroupId is a sound destroy witness on this pin: probed directly against ghcr.io/lex00/floci@sha256:c55d74e1 with no tofu in the loop, a delete-then-recreate under an identical group name minted sg-8c824b212636a50e9 -> sg-61cec558a8a5a286d. BREAK_COUNT=1 asserts the WRONG instance (count_test[0]) was destroyed and reports fail, so these checks discriminate. |
| Replace with create_before_destroy | pass | 1m13s | choudoufu: changing module.server’s image input (ubuntu2204 -> ubuntu2404, both real, both in floci’s seeded AMI catalog) proposed exactly one instance replace at the same declared address, cascading into the volume attachment (instance_id is ForceNew there too) - 2 to add, 0 to change, 2 to destroy, matching F-ORACLE’s own plan shape; applied cleanly; the old instance is confirmed terminated via the AWS CLI and the new instance is confirmed running the new image; the local record store’s record at the same address now names the new instance’s id, not the terminated one (i-8f50648fda377f32f -> i-3f01047f17dc5ad32); the next plan proposes no resource action; BREAK=replace confirms this section’s own record check discriminates (a deliberately-wrong expectation against the same real record fails, rather than vacuously passing). Scope note: this exercises OpenTofu’s default destroy-then-create ordering, not the create_before_destroy variant the stage’s Title names - see this section’s own header comment. A manufactured live-object collision (the shape ec2-instance-complete’s and corpus-sqs-basic’s own BREAK=replace controls report) has no tag surface to be detected from on this markers=record instance and is not exercised here - verified directly that an untagged extra instance is simply invisible to this plan, correctly, not incorrectly. |
| Crash between create and destroy | not run | ||
| Teardown | not run | ||
| Plan, review, apply | pass | 54s | one argument edited (aws_internet_gateway.crossing’s tags gain Reviewed=yes - one of this crossing’s seven tag-stamped objects, chosen over module.server’s markers = record instance and volume, which carry sumaform’s own lifecycle { ignore_changes = [tags] } and so could not witness a tag edit at all), “plan -out=approved.tfplan” wrote a 48579-byte stock-format plan file whose whole change set is one update on aws_internet_gateway.crossing (igw-dc04e058); the world then moved out of band (vpc-d2ee9e77’s Name tag through the AWS CLI, never through choudoufu - STAGE 5’s own proven mutation, on a DIFFERENT instance and a DIFFERENT live object from the one under review) and “apply approved.tfplan” refused with “The approved plan no longer matches the live system” at exit 3, classifying the drift under “This apply would do, and the approved plan does not include:” and naming both aws_vpc.crossing and the live vpc-d2ee9e77 it was computed against, with “Exit status 3” spelled out for a pipeline; nothing was applied - describe-tags on igw-dc04e058 still returned no Reviewed tag, read back through the AWS CLI rather than from the absence of an “Apply complete!” line. Inverted control on the same run (the shape live/smoke/scenarios/apply-what-was-approved.sh reasons out): with the Name tag put back and nothing else changed, the IDENTICAL file applied - 0 added, 1 changed, 0 destroyed - and igw-dc04e058 read back with Reviewed=yes, so the refusal is earned by the drift and not handed out to every plan file. The edit was then reverted, re-applied, the gateway confirmed to be the same id it started as, module.server’s record-based instance identity confirmed untouched, and the estate replanned empty, so PART F starts where it would have. BREAK_APPROVAL=1 asserts stage 12’s own recorded Break line (apply the planfile after a mutation and expect success) and correctly fails |
| Greenfield apply | pass | 2m21s | 11 resources from nothing (7 tag-stamped, 2 recorded via markers = record, 2 untaggable/derived - route_table_association and volume_attachment), replan empty, stock oracle in its own namespace matches on vpc cidr, security-group rule counts and the instance’s ami+type |
| Strict profile (not a headline stage) | not run |
Last run at commit 933618dec4 on 2026-09-08T22:17:50Z, exit code 0, against emulator image ghcr.io/lex00/floci@sha256:a39185cc3971d0188663d61043cb038dff1260d8a975b1aa72c4e2bb1feac3cb. Stale: the current pin is ghcr.io/lex00/floci@sha256:d9207de14c919f4bfa50e956376cc441970f3679aabfdd43f3dbf4b779b20805. Total run time 10m29.1s.
Oracle: stock terraform 1.16.1, stock tofu 1.12.6 (matches the current pin).
Landed d583dc93b7 (2026-08-18) - the FIRST OpenTofu-native estate crossed (uyuni-project’s own maintainers describe it as “OpenTofu configuration,” not “Terraform configuration”), versus every prior estate tonight being Terraform-authored/OpenTofu-compatible via terraform-aws-modules. Deliberately reduced slice: the full main.tf.aws.example composes four AWS host roles from one leaf module, backend_modules/aws/host, but three of the four (bastion, module.mirror, module.minion) have no root-facing toggle to disable real SSH/Salt provisioning - the “real boot behavior, out of scope for an emulator” case. Only module.server exposes provision=false; module.base’s own network submodule was also unusable (create_network=true needs CreateDhcpOptions/ReplaceRouteTableAssociation, neither implemented in floci), so this estate’s own plain VPC/subnet/NAT resources stand in for it. A real floci gap found and fixed on the way: sumaform’s ami.tf evaluates ~23 data “aws_ami” blocks unconditionally (one per supported guest OS) regardless of which single image an estate actually launches, and floci’s catalog had zero SUSE/Marketplace/Rocky/RHEL entries - seeded 20, reconciled into the combined image alongside tonight’s other three floci fixes. cold_deploy and migrate genuinely pass (11 resources, 9 of 11 stamped - 2 correctly untaggable). test_plan blocked by two real, structural rules baked into backend_modules/aws/host itself (the one leaf module every AWS host role shares, so this isn’t an artifact of the reduced slice), and on reading both rules’ own reasoning neither looks like a choudoufu defect - both are correct, deliberate refusals, not filed: (1) an unconditional, provisioner-less connection block that checkProvisioners flags on its own terms by documented design, dead code in sumaform’s own module; (2) lifecycle { ignore_changes = [tags] } on the WHOLE tags argument of aws_instance.instance and aws_ebs_volume.data_disk - sumaform’s own comment explains why (SUSE’s internal AWS accounts add tags on apply that need preserving), but ignoring the whole argument also silently discards the update that would write tofu-address/tofu-estate, the exact marker-safety failure #306 was about tonight. The fix sumaform’s own error text names - ignore_changes = [tags[“Owner”]], not the whole argument - is an edit to sumaform’s module, out of scope here. Follow-up pass 2026-08-18 (#313 cross-check, fresh worktree, real run): confirmed neither of the two RULE-classified refusals above is #313’s wall - zero occurrences of its diagnostic in the raw plan output. Both remain exactly as already documented: permanent, deliberate refusals (checkProvisioners on a dead-code connection block; ignore_changes on the whole tags argument), not filed as new issues, no action needed.
Reproduce it#
go run ./tools/gauntlet run corpus-sumaform-awsNeeds Docker (the emulator is pulled at the pinned digest), the AWS CLI, and a
stock terraform or tofu binary on PATH for the cold deploy. The script is
live/e2e/corpus-sumaform-aws/run.sh; BREAK=1 corrupts its assertions to show they are load-bearing.