WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmd/podman/containers/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/containers/podman/v6/cmd/podman/common"
"github.com/containers/podman/v6/cmd/podman/registry"
"github.com/containers/podman/v6/cmd/podman/utils"
"github.com/containers/podman/v6/internal/localapi"
"github.com/containers/podman/v6/libpod/define"
"github.com/containers/podman/v6/pkg/domain/entities"
"github.com/containers/podman/v6/pkg/specgen"
Expand Down Expand Up @@ -159,6 +160,7 @@ func create(cmd *cobra.Command, args []string) error {
if err := specgenutil.FillOutSpecGen(s, &cliVals, args); err != nil {
return err
}
localapi.WarnIfMachineVolumesUnavailable(registry.PodmanConfig(), cliVals.Volume)
s.RawImageName = rawImageName

// Include the command used to create the container.
Expand Down
2 changes: 2 additions & 0 deletions cmd/podman/containers/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/containers/podman/v6/cmd/podman/common"
"github.com/containers/podman/v6/cmd/podman/registry"
"github.com/containers/podman/v6/cmd/podman/utils"
"github.com/containers/podman/v6/internal/localapi"
"github.com/containers/podman/v6/libpod/define"
"github.com/containers/podman/v6/pkg/domain/entities"
"github.com/containers/podman/v6/pkg/rootless"
Expand Down Expand Up @@ -205,6 +206,7 @@ func run(cmd *cobra.Command, args []string) error {
if err := specgenutil.FillOutSpecGen(s, &cliVals, args); err != nil {
return err
}
localapi.WarnIfMachineVolumesUnavailable(registry.PodmanConfig(), cliVals.Volume)
s.RawImageName = rawImageName

// Include the command used to create the container.
Expand Down
116 changes: 116 additions & 0 deletions internal/localapi/machine_volume_warning.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
//go:build amd64 || arm64

package localapi

import (
"net/url"
"path/filepath"
"sort"
"strings"

"github.com/containers/podman/v6/pkg/domain/entities"
"github.com/containers/podman/v6/pkg/machine/define"
"github.com/containers/podman/v6/pkg/machine/vmconfigs"
"github.com/containers/podman/v6/pkg/specgen"
"github.com/sirupsen/logrus"
)

const machineVolumesDocURL = "https://docs.podman.io/en/latest/markdown/podman-machine-init.1.html#volume"

// WarnIfMachineVolumesUnavailable inspects bind mounts requested via --volume
// and warns if the source paths are not shared with the active Podman machine.
func WarnIfMachineVolumesUnavailable(cfg *entities.PodmanConfig, volumeSpecs []string) {
if cfg == nil || len(volumeSpecs) == 0 || !cfg.MachineMode {
return
}

parsedURI, err := url.Parse(cfg.URI)
if err != nil {
logrus.Debugf("skipping machine volume check, invalid connection URI %q: %v", cfg.URI, err)
return
}

mounts, vmType, err := getMachineMountsAndVMType(cfg.URI, parsedURI)
if err != nil {
logrus.Debugf("skipping machine volume check: %v", err)
return
}
if vmType == define.WSLVirt {
// WSL mounts the drives automatically so a warning would be misleading.
return
}

missing := collectUnsharedHostPaths(volumeSpecs, mounts, vmType)
if len(missing) == 0 {
return
}
sort.Strings(missing)
logrus.Warnf("The following bind mount sources are not shared with the Podman machine and may not work: %s. See %s for details on configuring machine volumes.", strings.Join(missing, ", "), machineVolumesDocURL)
}

func collectUnsharedHostPaths(volumeSpecs []string, mounts []*vmconfigs.Mount, vmType define.VMType) []string {
unshared := []string{}
seen := make(map[string]struct{})
for _, spec := range volumeSpecs {
src, ok := extractBindMountSource(spec)
if !ok {
continue
}
if _, found := isPathAvailableOnMachine(mounts, vmType, src); found {
continue
}
normalized, err := normalizeVolumeSource(src)
if err != nil {
logrus.Debugf("machine volume check: unable to normalize %q: %v", src, err)
continue
}
if _, exists := seen[normalized]; !exists {
unshared = append(unshared, normalized)
seen[normalized] = struct{}{}
}
}
return unshared
}

func extractBindMountSource(spec string) (string, bool) {
parts := specgen.SplitVolumeString(spec)
if len(parts) <= 1 {
return "", false
}
src := parts[0]
if len(src) == 0 {
return "", false
}
if strings.HasPrefix(src, "./") {
resolved, err := filepath.EvalSymlinks(src)
if err != nil {
logrus.Debugf("machine volume check: failed to resolve symlinks of %q: %v", src, err)
} else {
path, err := filepath.Abs(resolved)
if err != nil {
logrus.Debugf("machine volume check: failed to get absolute path of %q: %v", resolved, err)
} else {
src = path
}
}
}

if strings.HasPrefix(src, "/") || strings.HasPrefix(src, ".") || specgen.IsHostWinPath(src) {
return src, true
}
return "", false
}

func normalizeVolumeSource(path string) (string, error) {
if specgen.IsHostWinPath(path) {
return filepath.Clean(path), nil
}
if filepath.IsAbs(path) {
return filepath.Clean(path), nil
}
absPath, err := filepath.Abs(path)
if err != nil {
return "", err
}
return absPath, nil
}
12 changes: 12 additions & 0 deletions internal/localapi/machine_volume_warning_stub.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//go:build !amd64 && !arm64

package localapi

import (
"github.com/containers/podman/v6/pkg/domain/entities"
"github.com/sirupsen/logrus"
)

func WarnIfMachineVolumesUnavailable(_ *entities.PodmanConfig, _ []string) {
logrus.Debug("skipping machine volume check: podman machine mode not supported")
}
44 changes: 44 additions & 0 deletions internal/localapi/machine_volume_warning_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//go:build amd64 || arm64

package localapi

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

"github.com/containers/podman/v6/pkg/machine/define"
"github.com/containers/podman/v6/pkg/machine/vmconfigs"
)

func TestCollectUnsharedHostPaths(t *testing.T) {
t.Parallel()

tmp := t.TempDir()
shared := filepath.Join(tmp, "shared")
nested := filepath.Join(shared, "nested")
if err := os.MkdirAll(nested, 0o755); err != nil {
t.Fatalf("mkdir nested: %v", err)
}
unshared := filepath.Join(tmp, "unshared")

mounts := []*vmconfigs.Mount{
{Source: shared},
}

volumes := []string{
shared + ":/data",
nested + ":/nested",
unshared + ":/fail",
unshared + ":/fail2", // duplicate should only be reported once
"namedVolume:/ctr",
}

missing := collectUnsharedHostPaths(volumes, mounts, define.QemuVirt)
if len(missing) != 1 {
t.Fatalf("expected 1 missing mount, got %d (%v)", len(missing), missing)
}
if filepath.Clean(missing[0]) != filepath.Clean(unshared) {
t.Fatalf("expected missing path %q, got %q", unshared, missing[0])
}
}