Skip to content

feat(clean): Remove OS state by default#76

Open
aaljewarane wants to merge 2 commits into
aws:masterfrom
aaljewarane:clean-os-state
Open

feat(clean): Remove OS state by default#76
aaljewarane wants to merge 2 commits into
aws:masterfrom
aaljewarane:clean-os-state

Conversation

@aaljewarane

Copy link
Copy Markdown

Summary

ec2-macos-init clean now also invokes ec2-macos-utils system cleanup-state by default, with subprocess STDIO passed through to the calling shell. A new -init-state-only flag limits cleanup to init's own state.

This fixes the recurring issue where AMIs built after clean still carried macOS's cached network interface configuration (NetworkInterfaces.plist), delaying or breaking networking on instances launched from those images.

Behavior:

  • OS cleanup always runs (with or without init history), so a cleaned system is always ready for imaging. Absent instance history is treated as nothing to remove instead of a fatal error, and a history removal failure is logged, OS cleanup still runs, and clean exits non-zero so a partially cleaned system is never reported as success.
  • If ec2-macos-utils is missing or fails, clean exits non-zero with a pointer to -init-state-only; a half-cleaned image is the bug being fixed.
  • ec2-macos-utils is resolved from its install path (/usr/local/bin/ec2-macos-utils) first, falling back to PATH, since sudo's default PATH excludes /usr/local/bin for the documented sudo ec2-macos-init clean usage.

Dependency

Requires aws/ec2-macos-utils#41 to merge and release first.

Testing

  • Builds darwin/amd64 + arm64; go vet clean; existing tests pass.
  • Validated on mac1.metal (x86_64, macOS 15.7.7) and mac2.metal (arm64, macOS 26.3.1): removal, idempotence, plist regeneration on reboot, STDIO pass-through, -init-state-only opt-out, non-zero exit when utils is missing, history-failure ordering (OS cleanup still runs, then non-zero exit), install-path-preferred resolution, and PATH fallback.
  • End to end on mac1: clean -> AMI -> instance launched from the derived image booted with healthy networking and a clean first boot.

… now also removes well-known OS state by invoking 'ec2-macos-utils system cleanup-state' as a subprocess, with its output passed through to the calling shell. This removes state such as the macOS cached network interface configuration (NetworkInterfaces.plist) that breaks or delays networking on instances launched from a derived image (AMI). Pass -init-state-only to limit cleanup to ec2-macos-init's own state. Instance history removal no longer aborts the run: absent history is treated as nothing to remove, and a removal failure is logged, OS state cleanup still runs, and clean exits non-zero so a partially cleaned system is never reported as success. ec2-macos-utils is resolved from its install path (/usr/local/bin/ec2-macos-utils) first, falling back to PATH, since sudo's default PATH does not include /usr/local/bin for the documented 'sudo ec2-macos-init clean' usage.
@aaljewarane aaljewarane changed the title feat(clean): Remove cached OS state by default feat(clean): Remove OS state by default Jul 20, 2026
@aaljewarane

Copy link
Copy Markdown
Author

Note: Lint failures are pre-existing on master.

Comment thread clean.go Outdated
Comment on lines +67 to +70
err := cleanSystemState()
if err != nil {
c.Log.Fatalf(1, "Unable to remove OS state (re-run with -init-state-only to skip): %s", err)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way this is implemented now will break backwards compatibility with any setup that has an updated ec2-macos-init installation, but doesn't not the respectively updated ec2-macos-utils or even has a missing installation of ec2-macos-utils. This will cause breakages because the flag is an opt-out of the new behavior and not opt-in so the new call to ec2-macos-utils will be the new default behavior for any existing callers without updating their workflows.

I'd suggest we instead start with this being more gracefully handled and not error out if there are any issues calling ec2-macos-utils in favor of emitting warning logs. If you wanted, you could also have some finer error handling that's able to differentiate between ec2-macos-utils not being installed, not having the command, and having the command error out. That will allow us to gracefully handle the backwards compatibility cases while still erroring out if the tool call fails with its own error.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in b63e025. Missing utils and too-old utils (no system cleanup-state, probed via --help) both warn and continue; only a real command error fails. Can make the warn cases hard-fail later once customers have updated.

…state cleanup is opt-out default behavior, so systems without ec2-macos-utils, or with a version predating 'system cleanup-state', would break existing clean workflows on init update. Differentiate the cases: warn and continue when utils is absent or too old (probed via --help), and fail only when the command exists but errors. The lenient cases may become errors in a future release.
@aaljewarane

Copy link
Copy Markdown
Author

Validation on EC2 Mac hardware

Validated ec2-macos-init clean on:

Family Arch macOS
mac1.metal x86_64 15.7.7
mac2.metal arm64 26.3.1

New init built from this branch (b63e025). "Old utils" is a real build of ec2-macos-utils origin/main (f5848d0, predates system cleanup-state) — confirms the --help probe against genuine cobra behavior, not a mock. Identical results on both families.

Backwards-compat / three-case handling

Case Setup Expected Result
A new utils installed history + plist removed via delegation, STDIO passed through, exit 0 PASS
B old utils (no command) probe → warn + continue, exit 0, plist retained PASS
C no utils installed warn + continue, exit 0, plist retained PASS
D utils present, command errors hard-fail exit 1 (history already removed first) PASS

Original functionality + flag

Case Expected Result
default clean removes current instance history PASS
-init-state-only removes history, skips OS state, plist retained, exit 0 PASS
-all (multiple dirs) removes all instance history, exit 0 PASS
-all, history absent "nothing to remove", exit 0 PASS

Sample (case B, old utils):

Skipping OS state cleanup: installed ec2-macos-utils does not support 'system cleanup-state'
Cached OS state (e.g. NetworkInterfaces.plist) was not removed and may affect instances launched from an image of this system; update ec2-macos-utils to enable this cleanup
Clean complete   # exit 0

Sample (case D, real error):

Removing OS state with ec2-macos-utils
Unable to remove OS state: ec2-macos-utils system cleanup-state failed: exit status 1
Clean incomplete: unable to remove OS state: ...   # exit 1

Note: to avoid reboots, cases after the first real removal used a placeholder at the plist path; the Lstat+remove path is identical, and the first dry-run/removal exercised the genuine boot-generated plist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants