feat: add --dry-run flag to prepare and restore commands#147
feat: add --dry-run flag to prepare and restore commands#147tonyandrewmeyer merged 49 commits intocanonical:mainfrom
Conversation
Add a --dry-run flag that outputs what would happen without making system changes. Uses a hybrid approach where handlers announce intentions via Print() method, and DryRunWorker skips execution while delegating read operations to the real system for accurate conditional logic. - Add Print() method to Worker interface - Create DryRunWorker that skips execution but delegates reads - Add --dry-run flag to prepare and restore commands - Suppress logging output in dry-run mode - Add Print() calls throughout handlers for human-readable output - Add unit tests for dry-run functionality
- Fix manager_test.go to properly test DryRunWorker instead of MockSystem - Add integration tests for dry-run prepare and restore commands - Document in README that dry-run reads actual system state for accuracy Co-authored-by: tonyandrewmeyer <826522+tonyandrewmeyer@users.noreply.github.com>
feat: add dry-run option to prepare and restore (outstanding review comments)
…print lines. This also gives more similar 'you would execute this thing' type output, which I think is probably better.
The dry-run spread tests expected "Installing snap" and "Removing snap" messages, but after the refactoring to auto-print from DryRunWorker, the output now shows "Would run: snap install ..." and "Would run: snap remove ...". Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1. Load cached runtime config in dry-run restore mode for accuracy. When a user runs `prepare --extra-snaps=foo` followed by `restore --dry-run`, they now see that foo would be removed. Falls back to current config if no cached config exists. 2. Add Print() calls when bootstrapping/destroying Juju controllers. Previously only printed when skipping operations, now also prints when actually performing them for consistent dry-run output. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
The test now actually verifies that DryRunWorker delegates read operations to the underlying system: - User() returns data from the mock system - ReadFile() and ReadHomeDirFile() return mocked file contents - SnapInfo() and SnapChannels() return mocked snap data Also fixes: - Add missing 'path' import to dryrun.go (required after linter change) - Initialize mockSnapChannels map in NewMockSystem() Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
Parts of this were done with Claude Code (transcript), with a bunch of back-and-forth from me, and some hand-coding along the way. I then did a few series of reviews with Copilot in my fork, so am not bothering to do more of that here. |
|
Example run: |
benhoyt
left a comment
There was a problem hiding this comment.
Just leaving a few comments for now
|
Per discussion, let's change the output format so you can basically copy 'n' paste into a shell script. |
benhoyt
left a comment
There was a problem hiding this comment.
Looks good overall, and I really like the mostly-copy-n-pastable output. Several minor comments.
One other thing. I'm wondering if we can remove the /usr/bin and /usr/sbin prefix from lines like these:
/usr/bin/apt-get update
/usr/bin/apt-get install -y gnome-keyring
/usr/bin/apt-get install -y python3-pip
/usr/bin/apt-get install -y python3-venv
/usr/bin/snap install jhack --channel latest/stable
...
/usr/bin/chmod a+wr /var/snap/lxd/common/lxd/unix.socket
/usr/sbin/usermod -a -G lxd ben.hoyt@canonical.com
/usr/sbin/iptables -F FORWARD
/usr/sbin/iptables -P FORWARD ACCEPT
/usr/bin/snap install juju
I believe this comes from the fact that we do an exec.LookPath (basically which) and then store the full path. But it seems if we want to use LookPath to do a check, we could do that to check that the tool exists early, but then just throw away the path and exec the binary like chmod directly. (Or maybe we can just drop that altogether? I'm not sure.)
|
From the chat: something wrong with 2x |
|
I need to fix some things here. I'll ping you when it's ready for review again (I'll try to get it done before Monday). |
…those, and we have actual drynrun tests too, so this is really just pointless, so remove it.
Since we always succeed with commands in dry run mode, the technique where concierge will bootstrap until there is no error, relying on idempotent bootstrapping, doesn't really do what we want, since drynrun thinks that bootstrapping has already happened, but that is unlikely. so we output the command always in dry run mode. minor related change: instead of using 'which' to figure out if iptables is installed, use the native go functionality - because 'which' would always succeed.
|
Output for Output for Output for |
|
One change since you last reviewed: because Concierge does bootstrap by doing I changed it so that we always output the bootstrap commands, but that was the wrong call, I think. So now I've changed it so that users of |
Adds a
--dry-runflag that outputs what would happen (in a format that can be copy & pasted into a shell where possible) without making system changes.DryRunWorkerthat skips execution but delegates reads--dry-runflag toprepareandrestorecommandsfmt.Fprintlncalls inDryRunWorkerwhere execution is skippedFixes #61