Skip to content

Quadlet sugar#694

Merged
prestist merged 1 commit intocoreos:mainfrom
angelcerveraroldan:quadlet-sugar
Apr 21, 2026
Merged

Quadlet sugar#694
prestist merged 1 commit intocoreos:mainfrom
angelcerveraroldan:quadlet-sugar

Conversation

@angelcerveraroldan
Copy link
Copy Markdown
Member

@angelcerveraroldan angelcerveraroldan commented Mar 20, 2026

Basic sugar for quadlets. Allows for the following syntax:

variant: fcos
version: 1.8.0-experimental
systemd:
  quadlets:
    - name: sleepy-disk.container
      rootful: true
      contents_local: containers/sleepy.container
    - name: sleepy-infinity.container
      rootful: true
      contents: |
        [Unit]
        Description=A sleepy container
        [Container]
        ContainerName=sleepy-pod-inf
        Image=quay.io/fedora/fedora
        Exec=sleep infinity
        [Install]
        WantedBy=multi-user.target

I still need to add examples for the docs, and to run more tests.

Docs about quadlets can be found here.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces basic support for Podman quadlets, allowing their definition within the systemd configuration. The changes include extending the Systemd struct with a Quadlets field, defining a new Quadlet struct, and implementing the translation logic to convert quadlets into Ignition files or symlinks. Comprehensive validation has been added to ensure correct quadlet naming conventions and content sources. The new functionality is well-covered by unit tests, demonstrating handling of basic quadlets, template instances, local content, and error conditions. The implementation is clean and robust for the features introduced.

@angelcerveraroldan angelcerveraroldan force-pushed the quadlet-sugar branch 11 times, most recently from af44334 to 4f6f4ae Compare March 25, 2026 18:34
@angelcerveraroldan angelcerveraroldan marked this pull request as ready for review March 25, 2026 18:36
@angelcerveraroldan angelcerveraroldan added the sugar Issue related to config sugar label Mar 26, 2026
@angelcerveraroldan angelcerveraroldan force-pushed the quadlet-sugar branch 3 times, most recently from 339567f to 4961c66 Compare April 1, 2026 14:12
Copy link
Copy Markdown
Collaborator

@prestist prestist left a comment

Choose a reason for hiding this comment

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

Nice work overall, the approach follows existing patterns well (similar to trees and mount units). The validateNotTooManySources refactor is a clean improvement too.

A few things I noticed -- mostly around the user path semantics and some edge cases in the template instance logic. Also would be good to add a test for quadlet collisions with storage.files entries to make sure the nodeTracker catches those cross-section conflicts.

I see the PR description mentions still needing examples and more tests, so some of this might already be on your radar. Thank you for working on this!

Comment thread base/v0_8_exp/translate.go Outdated
func buildQuadletPath(isRoot bool, quadletName string) string {
const (
adminContainersPath = "/etc/containers/systemd"
userContainersPath = "/etc/containers/systemd/users"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Just want to make sure this is intentional -- per the podman docs, /etc/containers/systemd/users/ makes the quadlet run for all non-root users. If the intent is to target a specific user it would need to be /etc/containers/systemd/users/${UID}.

For ignition this is probably the right default, but might be worth calling out in the docs that rootful: false means "all users" and not a specific user.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes, this was by design. I actually was not sure wether we shuld just have /etc/containers/systemd/ and remove the users one. This would align more closely with ignition which does not save to /etc/systemd/user/. I do think that it may be good to keep it, as it is not a lot more code when compared to just having the one path.

Either way, I will have to document this.

if splitIndex == -1 {
return false, ""
}
extensionIndex := strings.LastIndex(name, ".")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What happens if name has no . at all (e.g. foo@bar)? LastIndex returns -1 and then splitIndex+1 == extensionIndex would be false, so we'd return true with a malformed template name. I know quadletExtension validation would catch it before we get here but this feels a bit fragile on its own.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The validation shuld catch this, as it checks for extension, to make the function less fragile, I have added a check for LastIndex == -1.

Comment thread base/v0_8_exp/validate.go Outdated
func (rs Quadlet) Validate(c path.ContextPath) (r report.Report) {
r = validateNotTooManySources(rs.ContentsLocal, rs.Contents, c)
// Template instances cannot have a content as they are symlinks
if isTemplateInstance, _ := isTemplateInstance(rs.Name); isTemplateInstance {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hmm, if a template instance has both contents AND contents_local set we would get ErrTooManySystemdSources from validateNotTooManySources and then also ErrTemplateInstanceCannotHaveContents here. Both errors are technically correct but might be worth adding a test case for that specific combo to make sure the report looks right.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ah, didn't think of this. I think if a template has both contents and contents_local, then ErrTooManySystemdSources would give an unhelpful message:

only one of the following can be set: contents, contents_local

I have changed it so that it just give two errors ErrTemplateInstanceCannotHaveContents, one for each of them.

@angelcerveraroldan angelcerveraroldan force-pushed the quadlet-sugar branch 5 times, most recently from 8978220 to 6ce50d3 Compare April 8, 2026 16:18
@prestist
Copy link
Copy Markdown
Collaborator

prestist commented Apr 14, 2026

Ah thank you for your quick edits! I was about to approve this but one small nit popped up. Can you update your commits to follow the convention of this repo? typically we name a file for folder followed by : and the change.

Just a small thing overall but its good to keep it consistent ex: 2bb9e42!

@angelcerveraroldan angelcerveraroldan force-pushed the quadlet-sugar branch 2 times, most recently from 7e953ce to b762d75 Compare April 14, 2026 16:52
Copy link
Copy Markdown
Collaborator

@prestist prestist left a comment

Choose a reason for hiding this comment

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

@angelcerveraroldan

So close with the commit names!

I think that it would be clear to have both of these commits to be squashed into one commit

Look at the sugar that has been added here 0d2fa0f

Copy link
Copy Markdown
Collaborator

@prestist prestist left a comment

Choose a reason for hiding this comment

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

LGTM thank you :)

@prestist prestist merged commit 9399e9c into coreos:main Apr 21, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

sugar Issue related to config sugar

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants