Part of #202.
Summary
Add the plumbing for per-distro GRUB fixups in the cidata seed without changing behavior for any current image. All KNOWN_IMAGES entries default to GrubFix::None; flipping them lands in the follow-up.
Changes
src/image.rs:
- Add
GrubFix enum:
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum GrubFix {
None,
GrubDefaultDropIn, // /etc/default/grub.d/ is sourced + update-grub
GrubDefaultInPlace, // edit /etc/default/grub + grub2-mkconfig
}
- Add
grub_fix: GrubFix field on KnownImage; default all rows to GrubFix::None for now.
- Thread
known.grub_fix through ensure_cidata_seed into the SeedSpec it constructs.
src/cloud_init.rs:
- Add structured fields on
SeedSpec so bhx-injected entries don't have to ride on extra_user_data:
pub runcmd: Vec<Vec<String>>,
pub write_files: Vec<WriteFile>,
pub grub_fix: GrubFix,
- Extend
render_user_data to emit single runcmd: and write_files: blocks built from those structured fields. extra_user_data continues to be appended verbatim — cloud-init's documented list_extend merge for duplicate top-level list keys should concat operator-supplied runcmd: onto bhx's, but verify in Issue C before claiming this works.
- Private helper per
GrubFix variant that emits the right runcmd + write_files entries:
GrubDefaultDropIn: write /etc/default/grub.d/99-bhx-console.cfg containing GRUB_CMDLINE_LINUX=\"\$GRUB_CMDLINE_LINUX console=hvc0\", GRUB_TIMEOUT_STYLE=menu, GRUB_TIMEOUT=5; runcmd [update-grub]. Use YAML block scalar (|) for the content to sidestep quoting.
GrubDefaultInPlace: runcmd seds /etc/default/grub to append console=hvc0 to GRUB_CMDLINE_LINUX, set GRUB_TIMEOUT_STYLE=menu, set GRUB_TIMEOUT=5; then grub2-mkconfig -o /boot/grub2/grub.cfg.
src/profile.rs:
- Only if it constructs
SeedSpec literals — default the new fields to empty / GrubFix::None.
Footguns / notes for the implementer
console=hvc0 must be appended, not prepended: the kernel's /dev/console symlink follows the last console= argument.
- Don't wrap the runcmd in
set -e. grub2-mkconfig exits non-zero on benign os-prober failures.
- One-line comment on the runcmd that it runs late enough for
/boot to be mounted — anyone tempted to move this to bootcmd "to be earlier" will silently break images with a separate /boot partition.
Test plan (hardware-free)
- Unit test: render
SeedSpec for each GrubFix variant; assert generated YAML matches a fixture string.
- Unit test: combine structured
runcmd with operator-supplied extra_user_data; parse the resulting YAML and confirm both runcmd: blocks are well-formed.
cargo fmt --check, cargo clippy --all-targets -- -D warnings, cargo test clean.
Acceptance
- CI gates clean.
- No
KNOWN_IMAGES entry changes behavior (all stay GrubFix::None).
- Renderer emits one
runcmd: and one write_files: block; YAML round-trips through serde_yaml or equivalent without errors.
Part of #202.
Summary
Add the plumbing for per-distro GRUB fixups in the cidata seed without changing behavior for any current image. All
KNOWN_IMAGESentries default toGrubFix::None; flipping them lands in the follow-up.Changes
src/image.rs:GrubFixenum:grub_fix: GrubFixfield onKnownImage; default all rows toGrubFix::Nonefor now.known.grub_fixthroughensure_cidata_seedinto theSeedSpecit constructs.src/cloud_init.rs:SeedSpecso bhx-injected entries don't have to ride onextra_user_data:render_user_datato emit singleruncmd:andwrite_files:blocks built from those structured fields.extra_user_datacontinues to be appended verbatim — cloud-init's documentedlist_extendmerge for duplicate top-level list keys should concat operator-suppliedruncmd:onto bhx's, but verify in Issue C before claiming this works.GrubFixvariant that emits the rightruncmd+write_filesentries:GrubDefaultDropIn: write/etc/default/grub.d/99-bhx-console.cfgcontainingGRUB_CMDLINE_LINUX=\"\$GRUB_CMDLINE_LINUX console=hvc0\",GRUB_TIMEOUT_STYLE=menu,GRUB_TIMEOUT=5; runcmd[update-grub]. Use YAML block scalar (|) for the content to sidestep quoting.GrubDefaultInPlace: runcmd seds/etc/default/grubto appendconsole=hvc0toGRUB_CMDLINE_LINUX, setGRUB_TIMEOUT_STYLE=menu, setGRUB_TIMEOUT=5; thengrub2-mkconfig -o /boot/grub2/grub.cfg.src/profile.rs:SeedSpecliterals — default the new fields to empty /GrubFix::None.Footguns / notes for the implementer
console=hvc0must be appended, not prepended: the kernel's/dev/consolesymlink follows the lastconsole=argument.set -e.grub2-mkconfigexits non-zero on benignos-proberfailures./bootto be mounted — anyone tempted to move this tobootcmd"to be earlier" will silently break images with a separate/bootpartition.Test plan (hardware-free)
SeedSpecfor eachGrubFixvariant; assert generated YAML matches a fixture string.runcmdwith operator-suppliedextra_user_data; parse the resulting YAML and confirm bothruncmd:blocks are well-formed.cargo fmt --check,cargo clippy --all-targets -- -D warnings,cargo testclean.Acceptance
KNOWN_IMAGESentry changes behavior (all stayGrubFix::None).runcmd:and onewrite_files:block; YAML round-trips throughserde_yamlor equivalent without errors.