Merge pull request #28970 from Luap99/v6.0
Some checks failed
ci / path-filter (push) Has been cancelled
ci / Validate source code changes (push) Has been cancelled
ci / Cross Build (Linux, FreeBSD) (push) Has been cancelled
ci / build debian-sid (push) Has been cancelled
ci / build fedora-current (push) Has been cancelled
ci / build fedora-prior (push) Has been cancelled
ci / build fedora-rawhide (push) Has been cancelled
ci / windows installer hyperv (push) Has been cancelled
ci / windows installer wsl (push) Has been cancelled
ci / macos installer (push) Has been cancelled
ci / int local root debian-sid (push) Has been cancelled
ci / sys local root debian-sid (push) Has been cancelled
ci / int local rootless debian-sid (push) Has been cancelled
ci / sys local rootless debian-sid (push) Has been cancelled
ci / int remote root debian-sid (push) Has been cancelled
ci / sys remote root debian-sid (push) Has been cancelled
ci / bud local root fedora-current (push) Has been cancelled
ci / int local root fedora-current (push) Has been cancelled
ci / sys local root fedora-current (push) Has been cancelled
ci / int local rootless fedora-current (push) Has been cancelled
ci / sys local rootless fedora-current (push) Has been cancelled
ci / bud remote root fedora-current (push) Has been cancelled
ci / int remote root fedora-current (push) Has been cancelled
ci / sys remote root fedora-current (push) Has been cancelled
ci / int remote rootless fedora-current (push) Has been cancelled
ci / sys remote rootless fedora-current (push) Has been cancelled
ci / int local root fedora-prior (push) Has been cancelled
ci / sys local root fedora-prior (push) Has been cancelled
ci / int local rootless fedora-prior (push) Has been cancelled
ci / sys local rootless fedora-prior (push) Has been cancelled
ci / int remote root fedora-prior (push) Has been cancelled
ci / sys remote root fedora-prior (push) Has been cancelled
ci / int local root fedora-rawhide (push) Has been cancelled
ci / sys local root fedora-rawhide (push) Has been cancelled
ci / int local rootless fedora-rawhide (push) Has been cancelled
ci / sys local rootless fedora-rawhide (push) Has been cancelled
ci / int remote root fedora-rawhide (push) Has been cancelled
ci / sys remote root fedora-rawhide (push) Has been cancelled
ci / apiv2 root fedora-current (push) Has been cancelled
ci / bindings root fedora-current (push) Has been cancelled
ci / compose_v2 root fedora-current (push) Has been cancelled
ci / docker_py root fedora-current (push) Has been cancelled
ci / unit root fedora-current (push) Has been cancelled
ci / apiv2 rootless fedora-current (push) Has been cancelled
ci / compose_v2 rootless fedora-current (push) Has been cancelled
ci / unit rootless fedora-current (push) Has been cancelled
ci / upgrade v5.3.1 root fedora-current (push) Has been cancelled
ci / upgrade v5.6.2 root fedora-current (push) Has been cancelled
ci / machine linux amd64 (push) Has been cancelled
ci / windows unit (push) Has been cancelled
ci / windows e2e (push) Has been cancelled
ci / windows machine hyperv (push) Has been cancelled
ci / windows machine wsl (push) Has been cancelled
ci / macos machine applehv (push) Has been cancelled
ci / macos machine libkrun (push) Has been cancelled
ci / Total Success (push) Has been cancelled

[v6.0] Some backports to fix CI flakes, one regression fix, and one small doc fix
This commit is contained in:
Matt Heon 2026-06-18 14:01:38 -04:00 committed by GitHub
commit f2c236b22f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 155 additions and 80 deletions

View file

@ -99,6 +99,7 @@ jobs:
with:
version: ${{ steps.gv.outputs.version }}
install-only: true
skip-cache: true # cache causes flaky results https://github.com/podman-container-tools/podman/issues/28893
- name: Install pre-commit
run: pipx install pre-commit

View file

@ -42,7 +42,7 @@ For rootful use:
sudo cp hello.container /etc/containers/systemd/
```
## Step 3: Reload and enable the service
## Step 3: Reload and start the service
For rootless use:
```bash
@ -53,9 +53,13 @@ systemctl --user start hello.service
For rootful use:
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now hello.service
sudo systemctl start hello.service
```
Note quadlet services cannot be enabled as they are a generated systemd unit,
see [podman-systemd.unit(5)](podman-systemd.unit.5.md#enabling-unit-files) for more information.
## Expected Output:
For rootless, check logs using:

View file

@ -6,7 +6,7 @@ SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
source "$SCRIPT_DIR/lib.sh"
AUTOMATION_RELEASE="20260520t200858z"
AUTOMATION_RELEASE="20260616t073924z" # TODO should be renovate managed
LIMA_VM_NAME=podman-ci
REPO_DIR="$SCRIPT_DIR/../.."

View file

@ -23,25 +23,13 @@ fi
# Nothing changed under test subdirectory.
#
# This is OK if the only files being touched are "safe" ones.
# This is OK if no source code files were changed.
# Also we allow vendor updated without tests so exclude the vendor files
# and also the version files so release PRs do not need tests.
filtered_changes=$(git diff --name-only $base $head |
grep -F -vx .cirrus.yml |
grep -F -vx .pre-commit-config.yaml |
grep -F -vx .gitignore |
grep -F -vx go.mod |
grep -F -vx go.sum |
grep -F -vx podman.spec.rpkg |
grep -F -vx .golangci.yml |
grep -F -vx winmake.ps1 |
grep -E -v '/*Makefile$' |
grep -E -v '^[^/]+\.md$' |
grep -E -v '^.github' |
grep -E -v '^contrib/' |
grep -E -v '^docs/' |
grep -E -v '^hack/' |
grep -E -v '^nix/' |
grep -E -v '^vendor/' |
grep -E -v '^version/')
grep -E -v '^(test/tools/)?vendor/' |
grep -E -v '^version/' |
grep -E -x '.*\.(go|c|h)')
if [[ -z "$filtered_changes" ]]; then
exit 0
fi

View file

@ -7,6 +7,38 @@ import (
"go.podman.io/podman/v6/pkg/systemd/parser"
)
// fcosDirSymlinks maps FCOS root-level symlinks to their real paths.
// FCOS symlinks several top-level dirs into /var for the read-only rootfs.
// systemd rejects a mount unit whose Where= traverses a symlink, so we
// resolve these before writing the ignition unit.
var fcosDirSymlinks = map[string]string{
"/home": "/var/home",
"/mnt": "/var/mnt",
"/opt": "/var/opt",
"/root": "/var/roothome",
"/srv": "/var/srv",
}
// canonicalizeFCOSMountTarget returns the canonical path for target by
// substituting any known FCOS root-level symlink prefix.
func canonicalizeFCOSMountTarget(target string) string {
// Guard check for empty strings or paths not starting with '/'
if len(target) < 2 || target[0] != '/' {
return target
}
// Find the end of the first path component (e.g. "/home" in "/home/alice").
end := 1
for end < len(target) && target[end] != '/' {
end++
}
if real, ok := fcosDirSymlinks[target[:end]]; ok {
return real + target[end:]
}
return target
}
// GenerateSystemDFilesForVirtiofsMounts generates the systemd unit files needed
// to mount virtiofs volumes inside a FCOS guest VM. It is shared between the
// AppleHV, LibKrun, and QEMU providers.
@ -30,10 +62,13 @@ func GenerateSystemDFilesForVirtiofsMounts(mounts []VirtIoFs) ([]ignition.Unit,
return nil, err
}
// Use the canonical path so systemd accepts the Where= value.
// On FCOS /home is a symlink to var/home; systemd rejects non-canonical paths.
canonicalTarget := canonicalizeFCOSMountTarget(mnt.Target)
virtiofsMount := ignition.Unit{
Enabled: ignition.BoolToPtr(true),
Name: fmt.Sprintf("%s.mount", parser.PathEscape(mnt.Target)),
Contents: ignition.StrToPtr(fmt.Sprintf(mountUnitFile, mnt.Tag, mnt.Target)),
Name: fmt.Sprintf("%s.mount", parser.PathEscape(canonicalTarget)),
Contents: ignition.StrToPtr(fmt.Sprintf(mountUnitFile, mnt.Tag, canonicalTarget)),
}
unitFiles = append(unitFiles, virtiofsMount)

View file

@ -0,0 +1,72 @@
package machine
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCanonicalizeFCOSMountTarget(t *testing.T) {
tests := []struct {
input string
expected string
}{
// Known FCOS symlinks — must be rewritten
{"/home/alice", "/var/home/alice"},
{"/home/alice/projects", "/var/home/alice/projects"},
{"/mnt/data", "/var/mnt/data"},
{"/opt/myapp", "/var/opt/myapp"},
{"/root", "/var/roothome"},
{"/root/.config", "/var/roothome/.config"},
{"/srv/www", "/var/srv/www"},
// Exact match on a symlinked dir itself
{"/home", "/var/home"},
{"/mnt", "/var/mnt"},
// Paths that do NOT start with a known symlink — unchanged
{"/var/home/alice", "/var/home/alice"},
{"/tmp/foo", "/tmp/foo"},
{"/data/work", "/data/work"},
{"/work", "/work"},
// Prefix collision guard: /homes should NOT match /home
{"/homes/alice", "/homes/alice"},
{"/rootfs", "/rootfs"},
}
for _, tt := range tests {
got := canonicalizeFCOSMountTarget(tt.input)
assert.Equal(t, tt.expected, got, "input: %q", tt.input)
}
}
func TestGenerateSystemDFilesForVirtiofsmountsCanonicalPath(t *testing.T) {
mounts := []VirtIoFs{
NewVirtIoFsMount("/home/alice", "/home/alice", false),
NewVirtIoFsMount("/data", "/data", false),
}
units, err := GenerateSystemDFilesForVirtiofsMounts(mounts)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
// First two units are the mount units; the rest are immutable-root helpers.
mountUnits := units[:2]
cases := []struct {
wantName string
wantWhere string
}{
// /home/alice must be rewritten to /var/home/alice
{"var-home-alice.mount", "/var/home/alice"},
// /data has no FCOS symlink — stays as-is
{"data.mount", "/data"},
}
for i, c := range cases {
u := mountUnits[i]
assert.Equal(t, c.wantName, u.Name, "unit[%d].Name", i)
if assert.NotNil(t, u.Contents, "unit[%d].Contents", i) {
assert.Contains(t, *u.Contents, "Where="+c.wantWhere, "unit[%d] missing Where=", i)
}
}
}

View file

@ -69,7 +69,7 @@ type PodmanTestIntegration struct {
SignaturePolicyPath string
CgroupManager string
Host HostOS
TmpDir string
CliTmpDir string // value of podman --tmpdir
}
var (
@ -363,11 +363,15 @@ func PodmanTestCreateUtil(tempDir string, target PodmanTestCreateUtilTarget) *Po
}
}
perTestTempDir := filepath.Join(tempDir, "ptemp")
err := os.Mkdir(perTestTempDir, 0o755)
Expect(err).ToNot(HaveOccurred())
p := &PodmanTestIntegration{
PodmanTest: PodmanTest{
PodmanBinary: podmanBinary,
RemotePodmanBinary: podmanRemoteBinary,
TempDir: tempDir,
TempDir: perTestTempDir,
RemoteTest: target != PodmanTestCreateUtilTargetLocal,
ImageCacheFS: storageFs,
ImageCacheDir: ImageCacheDir,
@ -376,7 +380,7 @@ func PodmanTestCreateUtil(tempDir string, target PodmanTestCreateUtilTarget) *Po
ConmonBinary: conmonBinary,
QuadletBinary: quadletBinary,
Root: root,
TmpDir: tempDir,
CliTmpDir: filepath.Join(tempDir, "clitmp"),
NetworkConfigDir: networkConfigDir,
OCIRuntime: ociRuntime,
RunRoot: filepath.Join(tempDir, "runroot"),
@ -1417,7 +1421,7 @@ func (p *PodmanTestIntegration) makeOptions(args []string, options PodmanExecOpt
"--conmon", p.ConmonBinary,
"--network-config-dir", p.NetworkConfigDir,
"--cgroup-manager", p.CgroupManager,
"--tmpdir", p.TmpDir,
"--tmpdir", p.CliTmpDir,
"--events-backend", eventsType,
)
@ -1547,11 +1551,8 @@ func (s *PodmanSessionIntegration) jq(jqCommand string) (string, error) {
}
func (p *PodmanTestIntegration) buildImage(dockerfile, imageName string, layers string, label string, extraOptions []string) string {
buildDir := filepath.Join(p.TempDir, "build"+stringid.GenerateRandomID())
err := os.Mkdir(buildDir, 0o755)
Expect(err).ToNot(HaveOccurred())
dockerfilePath := filepath.Join(buildDir, "Dockerfile-"+stringid.GenerateRandomID())
err = os.WriteFile(dockerfilePath, []byte(dockerfile), 0o644)
dockerfilePath := filepath.Join(p.TempDir, "Dockerfile-"+stringid.GenerateRandomID())
err := os.WriteFile(dockerfilePath, []byte(dockerfile), 0o755)
Expect(err).ToNot(HaveOccurred())
cmd := []string{"build", "--pull-never", "--layers=" + layers, "--file", dockerfilePath}
if label != "" {
@ -1563,7 +1564,7 @@ func (p *PodmanTestIntegration) buildImage(dockerfile, imageName string, layers
if len(extraOptions) > 0 {
cmd = append(cmd, extraOptions...)
}
cmd = append(cmd, buildDir)
cmd = append(cmd, p.TempDir)
session := p.Podman(cmd)
session.Wait(240)
Expect(session).Should(Exit(0), fmt.Sprintf("BuildImage session output: %q", session.OutputToString()))

View file

@ -10,17 +10,12 @@ import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
. "go.podman.io/podman/v6/test/utils"
"go.podman.io/storage/pkg/stringid"
)
func buildDataVolumeImage(pTest *PodmanTestIntegration, image, data, dest string) {
buildDir := filepath.Join(pTest.TempDir, "build"+stringid.GenerateRandomID())
err := os.Mkdir(buildDir, 0o755)
Expect(err).ToNot(HaveOccurred())
// Create a dummy file for data volume
dummyFile := filepath.Join(buildDir, data)
err = os.WriteFile(dummyFile, []byte(data), 0o644)
dummyFile := filepath.Join(pTest.TempDir, data)
err := os.WriteFile(dummyFile, []byte(data), 0o644)
Expect(err).ToNot(HaveOccurred())
// Create a data volume container image but no CMD binary in it
@ -28,11 +23,7 @@ func buildDataVolumeImage(pTest *PodmanTestIntegration, image, data, dest string
CMD doesnotexist.sh
ADD %s %s/
VOLUME %s/`, data, dest, dest)
containerFilePath := filepath.Join(buildDir, "Containerfile")
err = os.WriteFile(containerFilePath, []byte(containerFile), 0o644)
Expect(err).ToNot(HaveOccurred())
pTest.PodmanExitCleanly("build", "--pull-never", "-q", "-t", image, "--layers=false", "--file", containerFilePath)
pTest.BuildImage(containerFile, image, "false")
}
func createContainersConfFile(pTest *PodmanTestIntegration) {

View file

@ -133,7 +133,7 @@ func getRemoteOptions(p *PodmanTestIntegration, args []string) []string {
"--conmon", p.ConmonBinary,
"--network-config-dir", networkDir,
"--cgroup-manager", p.CgroupManager,
"--tmpdir", p.TmpDir,
"--tmpdir", p.CliTmpDir,
"--events-backend", "file",
}

View file

@ -38,12 +38,12 @@ var _ = Describe("Podman mount", func() {
opts := podmanTest.PodmanMakeOptions([]string{"mount", cid}, PodmanExecOptions{})
args = append(args, opts...)
// container root file system location is podmanTest.TempDir/...
// because "--root podmanTest.TempDir/..."
// container root file system location is podmanTest.Root/...
// because "--root podmanTest.Root/..."
session := podmanTest.Podman(args)
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring(podmanTest.TempDir))
Expect(session.OutputToString()).To(ContainSubstring(podmanTest.Root))
})
It("podman image mount", func() {
@ -61,11 +61,11 @@ var _ = Describe("Podman mount", func() {
opts := podmanTest.PodmanMakeOptions([]string{"image", "mount", CITEST_IMAGE}, PodmanExecOptions{})
args = append(args, opts...)
// image location is podmanTest.TempDir/... because "--root podmanTest.TempDir/..."
// image location is podmanTest.Root/... because "--root podmanTest.Root/..."
session := podmanTest.Podman(args)
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring(podmanTest.TempDir))
Expect(session.OutputToString()).To(ContainSubstring(podmanTest.Root))
// We have to unmount the image again otherwise we leak the tmpdir
// as active mount points cannot be removed.

View file

@ -5694,7 +5694,7 @@ spec:
playKube := podmanTest.Podman([]string{"kube", "play", kubeYaml})
playKube.WaitWithDefaultTimeout()
Expect(playKube).Should(ExitWithError(125, fmt.Sprintf("securejoin.OpenInRoot testing/onlythis: openat2 %s/root/volumes/testvol/_data/testing/onlythis: no such file or directory", podmanTest.TempDir)))
Expect(playKube).Should(ExitWithError(125, fmt.Sprintf("securejoin.OpenInRoot testing/onlythis: openat2 %s/volumes/testvol/_data/testing/onlythis: no such file or directory", podmanTest.Root)))
})
It("with unsafe hostPath subpaths", func() {

View file

@ -20,7 +20,6 @@ import (
"go.podman.io/common/pkg/sysinfo"
"go.podman.io/podman/v6/pkg/util"
. "go.podman.io/podman/v6/test/utils"
"go.podman.io/storage/pkg/stringid"
)
var _ = Describe("Podman pod create", func() {
@ -176,12 +175,8 @@ var _ = Describe("Podman pod create", func() {
Describe("podman create pod with --hosts-file", func() {
BeforeEach(func() {
buildDir := filepath.Join(podmanTest.TempDir, "build"+stringid.GenerateRandomID())
err := os.Mkdir(buildDir, 0o755)
Expect(err).ToNot(HaveOccurred())
imageHosts := filepath.Join(buildDir, "pause_hosts")
err = os.WriteFile(imageHosts, []byte("56.78.12.34 image.example.com"), 0o755)
imageHosts := filepath.Join(podmanTest.TempDir, "pause_hosts")
err := os.WriteFile(imageHosts, []byte("56.78.12.34 image.example.com"), 0o755)
Expect(err).ToNot(HaveOccurred())
configHosts := filepath.Join(podmanTest.TempDir, "hosts")
@ -196,16 +191,11 @@ var _ = Describe("Podman pod create", func() {
podmanTest.RestartRemoteService()
}
containerfile := strings.Join([]string{
dockerfile := strings.Join([]string{
`FROM ` + INFRA_IMAGE,
`COPY pause_hosts /etc/hosts`,
}, "\n")
containerFilePath := filepath.Join(buildDir, "Containerfile")
err = os.WriteFile(containerFilePath, []byte(containerfile), 0o644)
Expect(err).ToNot(HaveOccurred())
podmanTest.PodmanExitCleanly("build", "-q", "-t", "foobar.com/hosts_test_pause:latest", "--layers=false", "--no-hosts", buildDir)
podmanTest.BuildImage(dockerfile, "foobar.com/hosts_test_pause:latest", "false", "--no-hosts")
})
It("--hosts-file=path", func() {

View file

@ -69,18 +69,11 @@ func pullChunkedTests() { // included in pull_test.go, must use a Ginkgo DSL at
registryRef: pullChunkedRegistryPrefix + "chunked-normal",
dirPath: filepath.Join(imageDir, "chunked-normal"),
}
buildDir := filepath.Join(podmanTest.TempDir, "build")
err := os.Mkdir(buildDir, 0o755)
Expect(err).ToNot(HaveOccurred())
chunkedNormalContentPath := "chunked-normal-image-content"
err = os.WriteFile(filepath.Join(buildDir, chunkedNormalContentPath), fmt.Appendf(nil, "content-%d", rand.Int64()), 0o600)
err := os.WriteFile(filepath.Join(podmanTest.TempDir, chunkedNormalContentPath), fmt.Appendf(nil, "content-%d", rand.Int64()), 0o600)
Expect(err).NotTo(HaveOccurred())
chunkedNormalContainerFile := fmt.Sprintf("FROM scratch\nADD %s /content", chunkedNormalContentPath)
err = os.WriteFile(filepath.Join(buildDir, "Containerfile"), []byte(chunkedNormalContainerFile), 0o600)
Expect(err).NotTo(HaveOccurred())
podmanTest.PodmanExitCleanly("build", "-q", "-t", chunkedNormal.localTag(), "--layers=true", buildDir)
podmanTest.BuildImage(chunkedNormalContainerFile, chunkedNormal.localTag(), "true")
podmanTest.PodmanExitCleanly("push", "-q", "--tls-verify=false", "--force-compression", "--compression-format=zstd:chunked", chunkedNormal.localTag(), chunkedNormal.registryRef)
skopeo := SystemExec("skopeo", []string{"copy", "-q", "--preserve-digests", "--all", "--src-tls-verify=false", chunkedNormal.registryRef, "dir:" + chunkedNormal.dirPath})
skopeo.WaitWithDefaultTimeout()

View file

@ -135,7 +135,7 @@ var _ = Describe("Podman run with volumes", func() {
})
It("podman run with conflicting volumes errors", func() {
mountPath := filepath.Join(podmanTest.TmpDir, "secrets")
mountPath := filepath.Join(podmanTest.TempDir, "secrets")
err := os.Mkdir(mountPath, 0o755)
Expect(err).ToNot(HaveOccurred())
session := podmanTest.Podman([]string{"run", "-v", mountPath + ":" + dest, "-v", "/tmp" + ":" + dest, ALPINE, "ls"})

View file

@ -144,7 +144,7 @@ $c2[ ]\+tcp://localhost:54321[ ]\+true[ ]\+true" \
# Stop server. Use 'run' to avoid failing on nonzero exit status
run kill $_SERVICE_PID
run wait $_SERVICE_PID
wait $_SERVICE_PID || true
_SERVICE_PID=
run_podman system connection rm fakeconnect
@ -205,7 +205,7 @@ $c2[ ]\+tcp://localhost:54321[ ]\+true[ ]\+true" \
# Stop server. Use 'run' to avoid failing on nonzero exit status
run kill $_SERVICE_PID
run wait $_SERVICE_PID
wait $_SERVICE_PID || true
_SERVICE_PID=
run_podman system connection rm fakeconnect
@ -270,7 +270,7 @@ $c2[ ]\+tcp://localhost:54321[ ]\+true[ ]\+true" \
# Stop server. Use 'run' to avoid failing on nonzero exit status
run kill $_SERVICE_PID
run wait $_SERVICE_PID
wait $_SERVICE_PID || true
_SERVICE_PID=
run_podman system connection rm fakeconnect

View file

@ -67,7 +67,7 @@ type PodmanTest struct {
RemoteTLSClientKeyFile string
RemoteTLSDetails string
RemoteTest bool
TempDir string
TempDir string // TempDir is a unique per test directory.
}
// PodmanSession wraps the gexec.session so we can extend it