Skip to content

Commit

Permalink
Merge pull request #18446 from rhatdan/quadlet
Browse files Browse the repository at this point in the history
Allow user quadlets to be stored under /etc
  • Loading branch information
openshift-merge-robot authored May 5, 2023
2 parents c74f9ad + 27891a6 commit ca3d450
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 15 deletions.
27 changes: 18 additions & 9 deletions cmd/quadlet/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"flag"
"fmt"
"os"
"os/user"
"path"
"path/filepath"
"strings"
Expand Down Expand Up @@ -98,24 +99,32 @@ func Debugf(format string, a ...interface{}) {
// This returns the directories where we read quadlet .container and .volumes from
// For system generators these are in /usr/share/containers/systemd (for distro files)
// and /etc/containers/systemd (for sysadmin files).
// For user generators these live in $XDG_CONFIG_HOME/containers/systemd
func getUnitDirs(user bool) []string {
// For user generators these can live in /etc/containers/systemd/users, /etc/containers/systemd/users/$UID, and $XDG_CONFIG_HOME/containers/systemd
func getUnitDirs(rootless bool) []string {
// Allow overdiding source dir, this is mainly for the CI tests
unitDirsEnv := os.Getenv("QUADLET_UNIT_DIRS")
if len(unitDirsEnv) > 0 {
return strings.Split(unitDirsEnv, ":")
}

dirs := make([]string, 0)
if user {
if configDir, err := os.UserConfigDir(); err == nil {
dirs = append(dirs, path.Join(configDir, "containers/systemd"))
if rootless {
configDir, err := os.UserConfigDir()
if err != nil {
fmt.Fprintf(os.Stderr, "Warning: %v", err)
return nil
}
dirs = append(dirs, path.Join(configDir, "containers/systemd"))
dirs = append(dirs, filepath.Join(quadlet.UnitDirAdmin, "users"))
u, err := user.Current()
if err != nil {
fmt.Fprintf(os.Stderr, "Warning: %v", err)
return dirs
}
} else {
dirs = append(dirs, quadlet.UnitDirAdmin)
dirs = append(dirs, quadlet.UnitDirDistro)
return append(dirs, filepath.Join(quadlet.UnitDirAdmin, "users", u.Uid))
}
return dirs
dirs = append(dirs, quadlet.UnitDirAdmin)
return append(dirs, quadlet.UnitDirDistro)
}

func isExtSupported(filename string) bool {
Expand Down
40 changes: 40 additions & 0 deletions cmd/quadlet/main_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package main

import (
"os"
"os/user"
"path"
"path/filepath"
"testing"

"github.com/containers/podman/v4/pkg/systemd/quadlet"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -40,3 +45,38 @@ func TestIsUnambiguousName(t *testing.T) {
assert.Equal(t, res, test.res, "%q", test.input)
}
}

func TestUnitDirs(t *testing.T) {
rootDirs := []string{
quadlet.UnitDirAdmin,
quadlet.UnitDirDistro,
}
unitDirs := getUnitDirs(false)
assert.Equal(t, unitDirs, rootDirs, "rootful unit dirs should match")

configDir, err := os.UserConfigDir()
assert.Nil(t, err)
u, err := user.Current()
assert.Nil(t, err)

rootlessDirs := []string{
path.Join(configDir, "containers/systemd"),
filepath.Join(quadlet.UnitDirAdmin, "users"),
filepath.Join(quadlet.UnitDirAdmin, "users", u.Uid),
}

unitDirs = getUnitDirs(true)
assert.Equal(t, unitDirs, rootlessDirs, "rootless unit dirs should match")

name, err := os.MkdirTemp("", "dir")
assert.Nil(t, err)
// remove the temporary directory at the end of the program
defer os.RemoveAll(name)

t.Setenv("QUADLET_UNIT_DIRS", name)
unitDirs = getUnitDirs(false)
assert.Equal(t, unitDirs, []string{name}, "rootful should use environment variable")

unitDirs = getUnitDirs(true)
assert.Equal(t, unitDirs, []string{name}, "rootless should use environment variable")
}
22 changes: 16 additions & 6 deletions docs/source/markdown/podman-systemd.unit.5.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## NAME

podman\-systemd.unit - systemd units using Podman quadlet
podman\-systemd.unit - systemd units using Podman Quadlet

## SYNOPSIS

Expand All @@ -15,6 +15,8 @@ podman\-systemd.unit - systemd units using Podman quadlet

### Podman user unit search path

* /etc/containers/systemd/users/
* /etc/containers/systemd/users/$(UID)
* $XDG_CONFIG_HOME/containers/systemd/
* ~/.config/containers/systemd/

Expand All @@ -38,6 +40,14 @@ Each file type has a custom section (for example, `[Container]`) that is handled
other sections will be passed on untouched, allowing the use of any normal systemd configuration options
like dependencies or cgroup limits.

For rootless containers, when administrators place Quadlet files in the
/etc/containers/systemd/users directory, all users' sessions will execute the
Quadlet when the login session begins. If the administrator places a Quadlet
file in the /etc/containers/systemd/user/${UID}/ directory, then only the
user with the matching UID will execute the Quadlet when the login
session gets started.


### Enabling unit files

The services created by Podman are considered transient by systemd, which means they don't have the same
Expand Down Expand Up @@ -145,7 +155,7 @@ Adds a device node from the host into the container. The format of this is
`HOST-DEVICE[:CONTAINER-DEVICE][:PERMISSIONS]`, where `HOST-DEVICE` is the path of
the device node on the host, `CONTAINER-DEVICE` is the path of the device node in
the container, and `PERMISSIONS` is a list of permissions combining 'r' for read,
'w' for write, and 'm' for mknod(2). The `-` prefix tells quadlet to add the device
'w' for write, and 'm' for mknod(2). The `-` prefix tells Quadlet to add the device
only if it exists on the host.

This key can be listed multiple times.
Expand Down Expand Up @@ -307,7 +317,7 @@ generally has the form `type=TYPE,TYPE-SPECIFIC-OPTION[,...]`.
As a special case, for `type=volume` if `source` ends with `.volume`, a Podman named volume called
`systemd-$name` will be used as the source, and the generated systemd service will contain
a dependency on the `$name-volume.service`. Such a volume can be automatically be lazily
created by using a `$name.volume` quadlet file.
created by using a `$name.volume` Quadlet file.

This key can be listed multiple times.

Expand All @@ -320,7 +330,7 @@ not set up networking in the container.
As a special case, if the `name` of the network ends with `.network`, a Podman network called
`systemd-$name` will be used, and the generated systemd service will contain
a dependency on the `$name-network.service`. Such a network can be automatically
created by using a `$name.network` quadlet file.
created by using a `$name.network` Quadlet file.

This key can be listed multiple times.

Expand Down Expand Up @@ -449,7 +459,7 @@ If `SOURCE-VOLUME` starts with `.`, Quadlet will resolve the path relative to th
As a special case, if `SOURCE-VOLUME` ends with `.volume`, a Podman named volume called
`systemd-$name` will be used as the source, and the generated systemd service will contain
a dependency on the `$name-volume.service`. Such a volume can be automatically be lazily
created by using a `$name.volume` quadlet file.
created by using a `$name.volume` Quadlet file.

This key can be listed multiple times.

Expand Down Expand Up @@ -498,7 +508,7 @@ not set up networking in the container.
As a special case, if the `name` of the network ends with `.network`, a Podman network called
`systemd-$name` will be used, and the generated systemd service will contain
a dependency on the `$name-network.service`. Such a network can be automatically
created by using a `$name.network` quadlet file.
created by using a `$name.network` Quadlet file.

This key can be listed multiple times.

Expand Down

0 comments on commit ca3d450

Please sign in to comment.