feat(plugins): add kernel and initrd plugins
Metadata
Current evaluation
Merged #5814 in 8f56d299d, adding a reworked post-core18 kernel plugin and a new initrd/UKI plugin; it supersedes #4302.
Resolution: closed resolved
Reason: PR #5814 was approved and merged as commit 8f56d299d, delivering the kernel and initrd plugins. It explicitly supersedes #4302; #5846 (3249bed8e) also resolved the model-selection issue that had blocked its spread tests.
Evaluated by: mr-cal-bot
No scores available.
Issue body
- [x] Have you followed the [guidelines for contributing](https://github.com/canonical/snapcraft/blob/main/CONTRIBUTING.md)?
- [x] Have you signed the [CLA](http://www.ubuntu.com/legal/contributors/)?
- [x] Have you successfully run `make lint`?
- [x] Have you successfully run `make test`?
---
Update/rework kernel plugin for releases later than core18. The plugin has been removed from the experimental plugins list.
Additionally, a new plugin named initrd is added which enables a simple process for having a part construct an initrd and, optionally, a UKI. This plugin is essentially a de facto requirement for any successful strategy for building kernel snaps, as the initrd is inextricably linked to both the kernel itself as well as the particular Ubuntu Core release one may be building a kernel snap for. This plugin provides a uniform and reproducible interface for building that requirement.
Earlier iterations of these plugins contained many options and very challenging to read and debug code. This work largely removes or consolidates those options to streamline the building workflow for snappers, and refactors most of the critical functionality to discrete and independent scripts. This makes the plugin's behavior easier to debug and more closely resembles the kind of behavior one would have to implement in an `override` of some sort to replicate this behavior.
Some rudimentary tests have been written but these are not finished.
Still working on some failing tests.
Work done with @atomcult, they made sure my sh was up to snuff and my python wasn't Bad :)
Outstanding work:
- [x] Finish new behavior tests (non-legacy tests)
- [ ] [possibly] directly test script functions
- [ ] End-to-end tests of kernel/initrd builds, using image garden? Boot a fully-built image?
- [x] Add tests for building actual snaps (simple case, hard case. Already exist, just need adding).
- [x] https://github.com/dilyn-corner/snapcraft/pull/1#pullrequestreview-3291809835
- [x] Documentation
- [x] https://github.com/dilyn-corner/snapcraft/pull/1#discussion_r2393445187
- [x] Refactor/simplify mas?
- [x] https://github.com/dilyn-corner/snapcraft/pull/1#discussion_r2393445519
Supersedes #4302
---
<details>
<summary> Useful synopsis of how these plugins should work</summary>
### Overview
A quick description of each piece in some more substantive detail.
#### kernel
The kernel plugin accepts five options:
- kernel-kdefconfig
- provided as a list, default `["defconfig"]`
- can be any "usual" set of _config files in the "usual" locations
- kernel-kconfigflavour
- provided as a string, default `"generic"`
- Debian-kernel-specific, depends on the kernel source used
- kernel-kconfigs
- provided as a list, default `[]`
- kernel-enable-zfs-support
- bool, default `False`
- builds ZFS as out-of-tree kernel module
- kernel-enable-perf
- bool, default `False`
- builds the perf binary
The values of these options are directly passed to a build script. This build script is shared between both the legacy plugin and the current plugin. Currently this script is `snapcraft/parts/plugins/kernel_build.sh` and invoked by the plugin as `$SNAP/lib/python3.12/site-packages/snapcraft/parts/plugins/kernel_build.sh`. This location is just what "I" (snapcraft) chose.
The script itself does all the major kernel-y things. At a high level, it makes sure the "correct" config is generated (it breaks ties between defconfig, flavour, and kconfig as a developer would expect them to be done). It checks that the config supports the target (snaps, apparmor) but *does not* **fail** if the kernel wouldn't support those things - we assume you know what you're doing if you deviate from the default.
After some scaffolding, the kernel build is itself kicked off (with the relevant targets determined by the plugin, and the environment determined by the script).
The plugin does not assume that any other plugin will be used, but does make some opinionated choices. Specifically regarding the final location of everything it installs - the kernel image must be stored as `/kernel.img`, and the modules and firmware must be available in `/{firmware,modules}`. These are for snapd and Ubuntu Core.
Current limitations: basically none, although it isn't necessarily the most space-efficient (full `cp` instead of hard links may be used, for instance).
Previous versions of the plugin may supported other kernel options or kernel `source`s; these have been dropped and most behavior is now explicit aside from one key caveat: there is a "secret option" for a developer to provide their own `.config` for the kernel and skip config generation. This is not an option supported by the plugin directly but instead a thing the called script checks. It is **not** meant for end-users, but rather for developers trying to rapidly reproduce something (that is to say, nobody should be doing this in a production environment; they should be using the standard facilities explicitly supported by the plugin).
#### initrd
The initrd accepts three options for core22 and earlier bases:
- initrd-addons
- provided as a list, default `[]`
- allows adding arbitrary files, a specific example would be when adding FDE support to a kernel snap requires adding things like libTEEc and an `/bin/fde-reveal-key` etc
- initrd-firmware
- provided as a list, default `[]`
- these are firmware blobs which would be required specifically in the initrd. This is rarely necessary, but sometimes must be supported (and should be) - IYKYK
- initrd-modules
- provided as a list, default `[]`
- this list must include at a minimum what you need to mount the rootfs and exec `/bin/init` if they are built as modules for your target kernel, and these modules must be ABI compatible with that kernel - as such, the initrd and kernel plugins are tightly related (if you are using one, you are probably using the other)
Three more options are added for core24 and later:
- initrd-build-efi-image
- bool, default `False`
- if `True`, a `kernel.img` will be used from `$CRAFT_STAGE` to build a UKI (some UEFI binary containing the kernel/dtb and initrd, usuaully used on x86_64)
- initrd-efi-image-{cert,key}
- provided as a string, default is a snakeoil key/cert combo
- if provided, `initrd-build-efi-image` must be `True`. The key and cert would in this case be provided by the builder somehow, either through some override to the part using this plugin or via some part run before this one
The values of these options are directly passed to a build script. This build script is shared between both the legacy plugin and the current plugin. Currently this script is `snapcraft/parts/plugins/initrd_build.sh` and invoked by the plugin as `$SNAP/lib/python3.12/site-packages/snapcraft/parts/plugins/initrd_build.sh`. This location is just what "I" (snapcraft) chose.
The paths for the addons, firmware, and key/cert are all relative to `$CRAFT_STAGE/foo`, where foo is one of `addons/`, `firmware/`, or `signing/` as they are expected to be provided by other parts which build or otherwise supply these objects.
The script itself does some semi-complex things, as it must replicate the eventual runtime environment as it uses ubuntu-core-initramfs under the hood, and that tool operates similarly to other initramfs build tools.
A notable "odd" thing about this plugin is that it does a lot of its work in the `$CRAFT_PART_SRC` directory, *not* `$CRAFT_PART_BUILD`. This is largely done to improve the iterative build experience, as `$CRAFT_PART_SRC` won't be mangled if the build step for the part fails.
After some scaffolding (including constructing and preppiing a chroot for the target architecture), the initrd build itself is kicked off via ubuntu-core-initramfs. Most of the work this plugin does is to support using this tool, which is the official tool for building Ubuntu Core initrds.
The plugin does not assume that any other plugin will be used, but it does assume that other work has been done if some options are used; specifically the aforementioned `addons|firmware|signing` requirements.
Current limitations: the implementation is kind of shaky in that chroots can sometimes be unreliable; there are active bugs in LXD and fakechroot, and sometimes weird things happen (mostly, the PPA failing to be added to the chroot environment). These are outside the plugin's control, but have been reported to the appropriate upstreams. Workarounds have been done where required, and have been done in such a way that they are fine, just not "optimal" for certain circumstances. If you can't tell what I mean, then it worked ;) ).
Previous versions of this plugin may have supported other options. This implementation consolidates or removes those options, as it is more opinionated. Similar to the kernel plugin, this plugin provides a "secret option" for providing your own ubuntu-core-initramfs binary. This is intended only for testing changes to ubuntu-core-initramfs without burdening the developer of uploading those changes to some PPA (as this plugin does not support adding additional PPAs to the chroot environment, though this could be changed in the future). As such, this option remains undocumented and is **not** intended for end-users.
</details>
(any force pushes are after resolving all suggestions and fixing the history)
Evaluation history
| Date | Model | Scores | Action | Summary |
|---|---|---|---|---|
| stealth/space-bunny-alpha | — | closed resolved | Merged #5814 in 8f56d299d, adding a reworked post-core18 kernel plugin and a new initrd/UKI plugin; it supersedes #4302. | |
| stealth/space-bunny-alpha | — | closed resolved | Merged the reworked post-core18 kernel plugin and new initrd plugin in #5814 (8f56d299d), providing reproducible initrd and optional UKI builds and superseding #4302. | |
| qwen/qwen3.6-35b-a3b | — | — | Merged into a feature branch after simplifying kernel and initrd plugin logic and addressing review feedback. Unrelated spread test failures prompted a temporary merge to prevent staleness, with full integration pending upstream fixes. | |
| qwen3.6-35b-a3b-mtp-q6 | — | — | Merged into a feature branch pending unrelated spread test fixes. Introduces refactored kernel and initrd plugins for snapcraft, superseding #4302. Simplifies build workflows, consolidates options, and includes documentation and tests. |
Update history
No update history recorded yet.
Related work
-
Related To:
canonical/snapcraft#4302
(confidence 100%)
The earlier kernel/initrd plugin implementation was closed as superseded by #5814.
-
Blocked By:
canonical/snapcraft#5846
(confidence 95%)
Its model-selection fix was merged as 3249bed8e to resolve failures blocking #5814's spread tests.
Related issues
| Issue | Project | State | Summary | Similarity |
|---|---|---|---|---|
| #6284 feat: merge feature/kernel initrd plugin into main | snapcraft | merged | Merged into main as ceace05f3, adding kernel and initrd plugins for base core22 and higher. | |
| #6116 feat: kernel|initrd plugins: extend and improve behavior | snapcraft | merged | Merged via #6255 (6598b614e), expanding kernel/initrd plugin behavior and options; the feature branch then reached main through #6284 (ceace05f3). | |
| #6102 feat: kernel|initrd plugins: extend and improve behavior | snapcraft | closed | Superseded by #6110; cleaned-up kernel/initrd work landed through #6116 and was merged into main by #6284 (ceace05f3). | |
| #6254 feat(kernel,initrd): extend plugins with new options, stabilize | snapcraft | merged | PR #6254 merged as commit 518476fc1, adding kernel/initrd plugin options, stability fixes, docs and a new kernel-deb spread test; later landed on main via #6284 (ceace05f3). | |
| #6106 feat: add ubuntu core initrd plugin | snapcraft | closed | Closed unmerged as duplicate work; the parallel kernel/initrd implementation landed via #6284 (commit ceace05f3). | |
| #4302 plugins: kernel: split kernel plugin into kernel and initrd plugins | snapcraft | closed | PR #4302 (split kernel plugin into kernel + initrd plugins) was closed unmerged on 2025-10-14 by author kubiko as superseded by canonical/snapcraft#5814, merged in commit 8f56d299d. | |
| #3922 Add v2 and v3 kernel plugins | snapcraft | merged | PR #3922 by kubiko adding v2 and v3 (craft-parts) kernel plugins was merged as 2b0343c08 into the feature/kernel-plugin branch, published as latest/edge/kernel-plugin, then landed in main via #4111. | |
| #4057 Kernel plugin: reapplying missed fixes | snapcraft | merged | Merged PR #4057 fixed kernel-plugin initramfs handling for empty module lists, wildcard overlays, and UC20 module installation, clarified defaults, and updated tests. | |
| #6255 Feature/kernel initrd plugin merge | snapcraft | merged | Merged as commit 6598b614e: a main-into-feature-branch sync for the kernel/initrd plugin branch (after conflict cleanup), picking up #6254 (518476fc1). The branch later landed on main via #6284 (ceace05f3). | |
| #5437 Adding initrd plugin supporting UC20+ | snapcraft | closed | kubiko's initrd plugin PR (kernel .ko staging, firmware, EFI kernel images) sat unreviewed for ~1yr with failing tests/lint and was closed unmerged as superseded by canonical/snapcraft#5814, merged as 8f56d299d. |