From ca3341a4b70b7e58e19c96a99b9b56f55bf9021c Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 28 Apr 2026 13:43:07 +0200 Subject: [PATCH] [Test only] update for loading registries.d using shared configfile. Signed-off-by: Jan Kaluza --- go.mod | 6 + go.sum | 12 +- .../libcontainer/devices/device_deprecated.go | 20 ---- .../runc/libcontainer/devices/device_unix.go | 112 ------------------ .../common/pkg/parse/parse_unix.go | 2 +- .../image/v5/docker/registries_d.go | 108 +++++------------ .../storage/drivers/btrfs/btrfs.go | 82 +++++++------ .../storage/drivers/overlay/overlay.go | 80 +++++-------- .../storage/pkg/configfile/parse.go | 2 +- vendor/modules.txt | 10 +- 10 files changed, 125 insertions(+), 309 deletions(-) delete mode 100644 vendor/github.com/opencontainers/runc/libcontainer/devices/device_deprecated.go delete mode 100644 vendor/github.com/opencontainers/runc/libcontainer/devices/device_unix.go diff --git a/go.mod b/go.mod index 130d2dc3eda..a2e20de7f4f 100644 --- a/go.mod +++ b/go.mod @@ -135,3 +135,9 @@ require ( sigs.k8s.io/yaml v1.6.0 // indirect tags.cncf.io/container-device-interface/specs-go v1.1.0 // indirect ) + +replace go.podman.io/storage => github.com/jankaluza/container-libs/storage v0.0.0-20260428081533-0b40258c6c4e + +replace go.podman.io/common => github.com/jankaluza/container-libs/common v0.0.0-20260428081533-0b40258c6c4e + +replace go.podman.io/image/v5 => github.com/jankaluza/container-libs/image/v5 v5.0.0-20260428081533-0b40258c6c4e diff --git a/go.sum b/go.sum index 81cc12a19aa..030713bd7f9 100644 --- a/go.sum +++ b/go.sum @@ -125,6 +125,12 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jankaluza/container-libs/common v0.0.0-20260428081533-0b40258c6c4e h1:gIrWQ6Cq/1iUgYkxdtigJqkMDmt2tkJCa1kD0epjbAg= +github.com/jankaluza/container-libs/common v0.0.0-20260428081533-0b40258c6c4e/go.mod h1:iSyDl7NIIpWhCtvEIPpHWosWL/XygqeffWZU0WX0Io8= +github.com/jankaluza/container-libs/image/v5 v5.0.0-20260428081533-0b40258c6c4e h1:z85XrxzncrzhVWJkwmNMKB4oAC6O6xTelZplweJ8WGg= +github.com/jankaluza/container-libs/image/v5 v5.0.0-20260428081533-0b40258c6c4e/go.mod h1:sAszAH18v4KPpzPZdav9ovjEBcIDkmqdhbJV9SmnzfE= +github.com/jankaluza/container-libs/storage v0.0.0-20260428081533-0b40258c6c4e h1:sf6CEY3719vtn8oZkyaQqGI4Rm8VDL5wVW6XVoUj/TA= +github.com/jankaluza/container-libs/storage v0.0.0-20260428081533-0b40258c6c4e/go.mod h1:13aOBf6782/fbAzH7QNEqlVzFu+X4sS4MxDM/VdJGZU= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -285,12 +291,6 @@ go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfC go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= -go.podman.io/common v0.67.2-0.20260423135811-cbaa5f41e643 h1:WwUcVKPEUoSDiQ22osdYGqM3q9IDB4viqSASPCdw1K0= -go.podman.io/common v0.67.2-0.20260423135811-cbaa5f41e643/go.mod h1:kBztCGxEhou0OO0O4yJXAKC3JEQTmOxCJPni90+sQKY= -go.podman.io/image/v5 v5.39.3-0.20260423135811-cbaa5f41e643 h1:1LuhuiiXHHteVXULDV/x9qxJtFozQPLEYKHCbYdOuP0= -go.podman.io/image/v5 v5.39.3-0.20260423135811-cbaa5f41e643/go.mod h1:sAszAH18v4KPpzPZdav9ovjEBcIDkmqdhbJV9SmnzfE= -go.podman.io/storage v1.62.1-0.20260423135811-cbaa5f41e643 h1:/zmZ36KkCZumHK0EDH5QpSjyM3fY09YuyIfqoXxEI48= -go.podman.io/storage v1.62.1-0.20260423135811-cbaa5f41e643/go.mod h1:13aOBf6782/fbAzH7QNEqlVzFu+X4sS4MxDM/VdJGZU= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= diff --git a/vendor/github.com/opencontainers/runc/libcontainer/devices/device_deprecated.go b/vendor/github.com/opencontainers/runc/libcontainer/devices/device_deprecated.go deleted file mode 100644 index 9483f054dcd..00000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/devices/device_deprecated.go +++ /dev/null @@ -1,20 +0,0 @@ -package devices - -import "github.com/opencontainers/cgroups/devices/config" - -// Deprecated: use [github.com/opencontainers/cgroups/devices/config]. -const ( - Wildcard = config.Wildcard - WildcardDevice = config.WildcardDevice - BlockDevice = config.BlockDevice - CharDevice = config.CharDevice - FifoDevice = config.FifoDevice -) - -// Deprecated: use [github.com/opencontainers/cgroups/devices/config]. -type ( - Device = config.Device - Permissions = config.Permissions - Type = config.Type - Rule = config.Rule -) diff --git a/vendor/github.com/opencontainers/runc/libcontainer/devices/device_unix.go b/vendor/github.com/opencontainers/runc/libcontainer/devices/device_unix.go deleted file mode 100644 index 409e58e963d..00000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/devices/device_unix.go +++ /dev/null @@ -1,112 +0,0 @@ -//go:build !windows - -package devices - -import ( - "errors" - "os" - "path/filepath" - - "golang.org/x/sys/unix" -) - -// ErrNotADevice denotes that a file is not a valid linux device. -var ErrNotADevice = errors.New("not a device node") - -// Testing dependencies -var ( - unixLstat = unix.Lstat - osReadDir = os.ReadDir -) - -// DeviceFromPath takes the path to a device and its cgroup_permissions (which -// cannot be easily queried) to look up the information about a linux device -// and returns that information as a Device struct. -func DeviceFromPath(path, permissions string) (*Device, error) { - var stat unix.Stat_t - err := unixLstat(path, &stat) - if err != nil { - return nil, err - } - - var ( - devType Type - mode = stat.Mode - devNumber = uint64(stat.Rdev) //nolint:unconvert // Rdev is uint32 on e.g. MIPS. - major = unix.Major(devNumber) - minor = unix.Minor(devNumber) - ) - switch mode & unix.S_IFMT { - case unix.S_IFBLK: - devType = BlockDevice - case unix.S_IFCHR: - devType = CharDevice - case unix.S_IFIFO: - devType = FifoDevice - default: - return nil, ErrNotADevice - } - return &Device{ - Rule: Rule{ - Type: devType, - Major: int64(major), - Minor: int64(minor), - Permissions: Permissions(permissions), - }, - Path: path, - FileMode: os.FileMode(mode &^ unix.S_IFMT), - Uid: stat.Uid, - Gid: stat.Gid, - }, nil -} - -// HostDevices returns all devices that can be found under /dev directory. -func HostDevices() ([]*Device, error) { - return GetDevices("/dev") -} - -// GetDevices recursively traverses a directory specified by path -// and returns all devices found there. -func GetDevices(path string) ([]*Device, error) { - files, err := osReadDir(path) - if err != nil { - return nil, err - } - var out []*Device - for _, f := range files { - switch { - case f.IsDir(): - switch f.Name() { - // ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825 - // ".udev" added to address https://github.com/opencontainers/runc/issues/2093 - case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts", ".udev": - continue - default: - sub, err := GetDevices(filepath.Join(path, f.Name())) - if err != nil { - return nil, err - } - - out = append(out, sub...) - continue - } - case f.Name() == "console": - continue - } - device, err := DeviceFromPath(filepath.Join(path, f.Name()), "rwm") - if err != nil { - if errors.Is(err, ErrNotADevice) { - continue - } - if errors.Is(err, os.ErrNotExist) { - continue - } - return nil, err - } - if device.Type == FifoDevice { - continue - } - out = append(out, device) - } - return out, nil -} diff --git a/vendor/go.podman.io/common/pkg/parse/parse_unix.go b/vendor/go.podman.io/common/pkg/parse/parse_unix.go index ae534aec3cd..67089e9371b 100644 --- a/vendor/go.podman.io/common/pkg/parse/parse_unix.go +++ b/vendor/go.podman.io/common/pkg/parse/parse_unix.go @@ -7,8 +7,8 @@ import ( "os" "path/filepath" + "github.com/moby/sys/devices" "github.com/opencontainers/cgroups/devices/config" - "github.com/opencontainers/runc/libcontainer/devices" "go.podman.io/storage/pkg/unshare" ) diff --git a/vendor/go.podman.io/image/v5/docker/registries_d.go b/vendor/go.podman.io/image/v5/docker/registries_d.go index 53bbb53cb10..6fe612160bf 100644 --- a/vendor/go.podman.io/image/v5/docker/registries_d.go +++ b/vendor/go.podman.io/image/v5/docker/registries_d.go @@ -3,42 +3,29 @@ package docker import ( "errors" "fmt" - "io/fs" + "io" "net/url" - "os" "path" "path/filepath" - "strings" "github.com/opencontainers/go-digest" "github.com/sirupsen/logrus" "go.podman.io/image/v5/docker/reference" "go.podman.io/image/v5/internal/rootless" "go.podman.io/image/v5/types" - "go.podman.io/storage/pkg/fileutils" + "go.podman.io/storage/pkg/configfile" "go.podman.io/storage/pkg/homedir" + "go.podman.io/storage/pkg/unshare" "gopkg.in/yaml.v3" ) -// systemRegistriesDirPath is the path to registries.d, used for locating lookaside Docker signature storage. -// You can override this at build time with -// -ldflags '-X go.podman.io/image/v5/docker.systemRegistriesDirPath=$your_path' -var systemRegistriesDirPath = builtinRegistriesDirPath - -// builtinRegistriesDirPath is the path to registries.d. -// DO NOT change this, instead see systemRegistriesDirPath above. -const builtinRegistriesDirPath = etcDir + "/containers/registries.d" - -// userRegistriesDirPath is the path to the per user registries.d. -var userRegistriesDir = filepath.FromSlash(".config/containers/registries.d") - // defaultUserDockerDir is the default lookaside directory for unprivileged user var defaultUserDockerDir = filepath.FromSlash(".local/share/containers/sigstore") // defaultDockerDir is the default lookaside directory for root var defaultDockerDir = "/var/lib/containers/sigstore" -// registryConfiguration is one of the files in registriesDirPath configuring lookaside locations, or the result of merging them all. +// registryConfiguration is one of the files configuring lookaside locations, or the result of merging them all. // NOTE: Keep this in sync with docs/registries.d.md! type registryConfiguration struct { DefaultDocker *registryNamespace `yaml:"default-docker"` @@ -78,91 +65,56 @@ func SignatureStorageBaseURL(sys *types.SystemContext, ref types.ImageReference, // loadRegistryConfiguration returns a registryConfiguration appropriate for sys. func loadRegistryConfiguration(sys *types.SystemContext) (*registryConfiguration, error) { - dirPath := registriesDirPath(sys) - logrus.Debugf(`Using registries.d directory %s`, dirPath) - return loadAndMergeConfig(dirPath) -} - -// registriesDirPath returns a path to registries.d -func registriesDirPath(sys *types.SystemContext) string { - return registriesDirPathWithHomeDir(sys, homedir.Get()) -} - -// registriesDirPathWithHomeDir is an internal implementation detail of registriesDirPath, -// it exists only to allow testing it with an artificial home directory. -func registriesDirPathWithHomeDir(sys *types.SystemContext, homeDir string) string { - if sys != nil && sys.RegistriesDirPath != "" { - return sys.RegistriesDirPath - } - userRegistriesDirPath := filepath.Join(homeDir, userRegistriesDir) - if err := fileutils.Exists(userRegistriesDirPath); err == nil { - return userRegistriesDirPath - } - if sys != nil && sys.RootForImplicitAbsolutePaths != "" { - return filepath.Join(sys.RootForImplicitAbsolutePaths, systemRegistriesDirPath) + registriesFiles := configfile.File{ + Name: "registries", + Extension: "yaml", + DoNotLoadMainFiles: true, + DoNotUseExtensionForConfigName: true, + UserId: unshare.GetRootlessUID(), + ErrorIfNotFound: false, + } + if sys != nil { + registriesFiles.RootForImplicitAbsolutePaths = sys.RootForImplicitAbsolutePaths + if sys.RegistriesDirPath != "" { + registriesFiles.CustomConfigFileDropInDirectory = sys.RegistriesDirPath + logrus.Debugf(`Using registries.d directory %s`, registriesFiles.CustomConfigFileDropInDirectory) + } } - - return systemRegistriesDirPath -} - -// loadAndMergeConfig loads configuration files in dirPath -// FIXME: Probably rename to loadRegistryConfigurationForPath -func loadAndMergeConfig(dirPath string) (*registryConfiguration, error) { mergedConfig := registryConfiguration{Docker: map[string]registryNamespace{}} dockerDefaultMergedFrom := "" nsMergedFrom := map[string]string{} - - dir, err := os.Open(dirPath) - if err != nil { - if os.IsNotExist(err) { - return &mergedConfig, nil - } - return nil, err - } - configNames, err := dir.Readdirnames(0) - if err != nil { - return nil, err - } - for _, configName := range configNames { - if !strings.HasSuffix(configName, ".yaml") { - continue + for item, err := range configfile.Read(®istriesFiles) { + if err != nil { + return nil, err } - configPath := filepath.Join(dirPath, configName) - configBytes, err := os.ReadFile(configPath) + contents, err := io.ReadAll(item.Reader) if err != nil { - if errors.Is(err, fs.ErrNotExist) { - // file must have been removed between the directory listing - // and the open call, ignore that as it is a expected race - continue - } return nil, err } - + logrus.Debugf(`Reading registries signature storage configuration from %q`, item.Name) var config registryConfiguration - err = yaml.Unmarshal(configBytes, &config) - if err != nil { - return nil, fmt.Errorf("parsing %s: %w", configPath, err) + if err := yaml.Unmarshal(contents, &config); err != nil { + return nil, fmt.Errorf("parsing %s: %w", item.Name, err) } if config.DefaultDocker != nil { if mergedConfig.DefaultDocker != nil { return nil, fmt.Errorf(`Error parsing signature storage configuration: "default-docker" defined both in %q and %q`, - dockerDefaultMergedFrom, configPath) + dockerDefaultMergedFrom, item.Name) } mergedConfig.DefaultDocker = config.DefaultDocker - dockerDefaultMergedFrom = configPath + dockerDefaultMergedFrom = item.Name } - for nsName, nsConfig := range config.Docker { // includes config.Docker == nil + for nsName, nsConfig := range config.Docker { if _, ok := mergedConfig.Docker[nsName]; ok { return nil, fmt.Errorf(`Error parsing signature storage configuration: "docker" namespace %q defined both in %q and %q`, - nsName, nsMergedFrom[nsName], configPath) + nsName, nsMergedFrom[nsName], item.Name) } mergedConfig.Docker[nsName] = nsConfig - nsMergedFrom[nsName] = configPath + nsMergedFrom[nsName] = item.Name } } - return &mergedConfig, nil } diff --git a/vendor/go.podman.io/storage/drivers/btrfs/btrfs.go b/vendor/go.podman.io/storage/drivers/btrfs/btrfs.go index 4ba23c544e0..7b80c95131f 100644 --- a/vendor/go.podman.io/storage/drivers/btrfs/btrfs.go +++ b/vendor/go.podman.io/storage/drivers/btrfs/btrfs.go @@ -483,15 +483,20 @@ func (d *Driver) CreateFromTemplate(id, template string, templateIDMappings *idt // CreateReadWrite creates a layer that is writable for use as a container // file system. func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error { - return d.create(id, parent, opts, true) + return d.create(id, parent, opts, false) } // Create the filesystem with given id. func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error { - return d.create(id, parent, opts, false) + return d.create(id, parent, opts, true) } -func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, applyDriverDefaultQuota bool) error { +func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, readOnly bool) error { + quota, err := d.parseStorageOpt(opts, readOnly) + if err != nil { + return err + } + quotas := d.quotasDir() subvolumes := d.subvolumesDir() if err := os.MkdirAll(subvolumes, 0o700); err != nil { @@ -518,34 +523,14 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, applyDr } } - var storageOpt map[string]string - if opts != nil { - storageOpt = opts.StorageOpt - } - - var quotaSize uint64 - var needQuota bool - if _, ok := storageOpt["size"]; ok { - driver := &Driver{} - if err := d.parseStorageOpt(storageOpt, driver); err != nil { - return err - } - quotaSize = driver.options.size - needQuota = true - } - if !needQuota && applyDriverDefaultQuota && d.options.size > 0 { - quotaSize = d.options.size - needQuota = true - } - if needQuota { - layerDriver := &Driver{options: btrfsOptions{size: quotaSize}} - if err := d.setStorageSize(path.Join(subvolumes, id), layerDriver); err != nil { + if quota != nil { + if err := d.setStorageSize(path.Join(subvolumes, id), *quota); err != nil { return err } if err := os.MkdirAll(quotas, 0o700); err != nil { return err } - if err := os.WriteFile(path.Join(quotas, id), []byte(fmt.Sprint(quotaSize)), 0o644); err != nil { + if err := os.WriteFile(path.Join(quotas, id), []byte(fmt.Sprint(quota.size)), 0o644); err != nil { return err } } @@ -558,8 +543,27 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, applyDr return label.Relabel(path.Join(subvolumes, id), mountLabel, false) } -// Parse btrfs storage options -func (d *Driver) parseStorageOpt(storageOpt map[string]string, driver *Driver) error { +// layerQuota contains per-layer quota settings. +type layerQuota struct { + size uint64 +} + +// parseStorageOpt parses CreateOpts.StorageOpt. +// Returns a *layerQuota if a quota should be applied, nil otherwise. +func (d *Driver) parseStorageOpt(opts *graphdriver.CreateOpts, readOnly bool) (*layerQuota, error) { + var storageOpt map[string]string = nil // Iterating over a nil map is safe + if opts != nil { + storageOpt = opts.StorageOpt + } + + res := layerQuota{} + needQuota := false + + if !readOnly && d.options.size > 0 { + res.size = d.options.size + needQuota = true + } + // Read size to change the subvolume disk quota per container for key, val := range storageOpt { key := strings.ToLower(key) @@ -567,23 +571,27 @@ func (d *Driver) parseStorageOpt(storageOpt map[string]string, driver *Driver) e case "size": size, err := units.RAMInBytes(val) if err != nil { - return err + return nil, err } - driver.options.size = uint64(size) + res.size = uint64(size) + needQuota = true default: - return fmt.Errorf("unknown option %s (%q)", key, storageOpt) + return nil, fmt.Errorf("unknown option %s (%q)", key, storageOpt) } } - return nil + if needQuota { + return &res, nil + } + return nil, nil } // Set btrfs storage size -func (d *Driver) setStorageSize(dir string, driver *Driver) error { - if driver.options.size <= 0 { - return fmt.Errorf("btrfs: invalid storage size: %s", units.HumanSize(float64(driver.options.size))) +func (d *Driver) setStorageSize(dir string, quota layerQuota) error { + if quota.size <= 0 { + return fmt.Errorf("btrfs: invalid storage size: %s", units.HumanSize(float64(quota.size))) } - if d.options.minSpace > 0 && driver.options.size < d.options.minSpace { + if d.options.minSpace > 0 && quota.size < d.options.minSpace { return fmt.Errorf("btrfs: storage size cannot be less than %s", units.HumanSize(float64(d.options.minSpace))) } @@ -591,7 +599,7 @@ func (d *Driver) setStorageSize(dir string, driver *Driver) error { return err } - if err := subvolLimitQgroup(dir, driver.options.size); err != nil { + if err := subvolLimitQgroup(dir, quota.size); err != nil { return err } diff --git a/vendor/go.podman.io/storage/drivers/overlay/overlay.go b/vendor/go.podman.io/storage/drivers/overlay/overlay.go index 6a0eb210465..7647bf24540 100644 --- a/vendor/go.podman.io/storage/drivers/overlay/overlay.go +++ b/vendor/go.podman.io/storage/drivers/overlay/overlay.go @@ -991,46 +991,16 @@ func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts return fmt.Errorf("--storage-opt is supported only for overlay over xfs with 'pquota' mount option") } - if opts == nil { - opts = &graphdriver.CreateOpts{ - StorageOpt: map[string]string{}, - } - } - if d.options.forceMask != nil && d.options.mountProgram == "" { return fmt.Errorf("overlay: force_mask option for writeable layers is only supported with a mount_program") } - if _, ok := opts.StorageOpt["size"]; !ok { - if opts.StorageOpt == nil { - opts.StorageOpt = map[string]string{} - } - opts.StorageOpt["size"] = strconv.FormatUint(d.options.quota.Size, 10) - } - - if _, ok := opts.StorageOpt["inodes"]; !ok { - if opts.StorageOpt == nil { - opts.StorageOpt = map[string]string{} - } - opts.StorageOpt["inodes"] = strconv.FormatUint(d.options.quota.Inodes, 10) - } - return d.create(id, parent, opts, false) } // Create is used to create the upper, lower, and merge directories required for overlay fs for a given id. // The parent filesystem is used to configure these directories for the overlay. func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr error) { - if opts != nil && len(opts.StorageOpt) != 0 { - if _, ok := opts.StorageOpt["size"]; ok { - return fmt.Errorf("--storage-opt size is only supported for ReadWrite Layers") - } - - if _, ok := opts.StorageOpt["inodes"]; ok { - return fmt.Errorf("--storage-opt inodes is only supported for ReadWrite Layers") - } - } - return d.create(id, parent, opts, true) } @@ -1078,6 +1048,11 @@ func (d *Driver) getLayerPermissions(parent string, uidMaps, gidMaps []idtools.I } func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, readOnly bool) (retErr error) { + quota, err := d.parseStorageOpt(opts, readOnly) // Do this even for read-only layers, to allow rejecting quota options + if err != nil { + return err + } + dir, homedir, _ := d.dir2(id, readOnly) disableQuota := readOnly @@ -1127,19 +1102,6 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, readOnl }() if d.quotaCtl != nil && !disableQuota { - quota := quota.Quota{} - if opts != nil && len(opts.StorageOpt) > 0 { - driver := &Driver{} - if err := d.parseStorageOpt(opts.StorageOpt, driver); err != nil { - return err - } - if driver.options.quota.Size > 0 { - quota.Size = driver.options.quota.Size - } - if driver.options.quota.Inodes > 0 { - quota.Inodes = driver.options.quota.Inodes - } - } // Set container disk quota limit // If it is set to 0, we will track the disk usage, but not enforce a limit if err := d.quotaCtl.SetQuota(dir, quota); err != nil { @@ -1226,29 +1188,47 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, readOnl } // Parse overlay storage options -func (d *Driver) parseStorageOpt(storageOpt map[string]string, driver *Driver) error { +func (d *Driver) parseStorageOpt(opts *graphdriver.CreateOpts, readOnly bool) (quota.Quota, error) { + var storageOpt map[string]string = nil // Iterating over a nil map is safe + if opts != nil { + storageOpt = opts.StorageOpt + } + + res := quota.Quota{} + + if !readOnly { + res.Size = d.options.quota.Size + res.Inodes = d.options.quota.Inodes + } + // Read size to set the disk project quota per container for key, val := range storageOpt { key := strings.ToLower(key) switch key { case "size": + if readOnly { + return quota.Quota{}, fmt.Errorf("--storage-opt size is only supported for ReadWrite Layers") + } size, err := units.RAMInBytes(val) if err != nil { - return err + return quota.Quota{}, err } - driver.options.quota.Size = uint64(size) + res.Size = uint64(size) case "inodes": + if readOnly { + return quota.Quota{}, fmt.Errorf("--storage-opt inodes is only supported for ReadWrite Layers") + } inodes, err := strconv.ParseUint(val, 10, 64) if err != nil { - return err + return quota.Quota{}, err } - driver.options.quota.Inodes = inodes + res.Inodes = inodes default: - return fmt.Errorf("unknown option %s", key) + return quota.Quota{}, fmt.Errorf("unknown option %s", key) } } - return nil + return res, nil } func (d *Driver) getLower(parent string) (string, error) { diff --git a/vendor/go.podman.io/storage/pkg/configfile/parse.go b/vendor/go.podman.io/storage/pkg/configfile/parse.go index ad09f98fee0..eb397dcd929 100644 --- a/vendor/go.podman.io/storage/pkg/configfile/parse.go +++ b/vendor/go.podman.io/storage/pkg/configfile/parse.go @@ -384,7 +384,7 @@ func readDropInsFromPaths(paths []string, suffix string) ([]string, error) { return nil, err } for _, entry := range entries { - if entry.Type().IsRegular() && strings.HasSuffix(entry.Name(), suffix) { + if !entry.IsDir() && strings.HasSuffix(entry.Name(), suffix) { dropInMap[entry.Name()] = filepath.Join(path, entry.Name()) } } diff --git a/vendor/modules.txt b/vendor/modules.txt index 342a75f124d..d730b11b95e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -319,7 +319,6 @@ github.com/opencontainers/image-spec/specs-go/v1 github.com/opencontainers/runc/internal/linux github.com/opencontainers/runc/internal/pathrs github.com/opencontainers/runc/libcontainer/apparmor -github.com/opencontainers/runc/libcontainer/devices # github.com/opencontainers/runtime-spec v1.3.0 ## explicit github.com/opencontainers/runtime-spec/specs-go @@ -458,7 +457,7 @@ go.opentelemetry.io/otel/trace go.opentelemetry.io/otel/trace/embedded go.opentelemetry.io/otel/trace/internal/telemetry go.opentelemetry.io/otel/trace/noop -# go.podman.io/common v0.67.2-0.20260423135811-cbaa5f41e643 +# go.podman.io/common v0.67.2-0.20260423135811-cbaa5f41e643 => github.com/jankaluza/container-libs/common v0.0.0-20260428081533-0b40258c6c4e ## explicit; go 1.25.6 go.podman.io/common/internal go.podman.io/common/libimage @@ -509,7 +508,7 @@ go.podman.io/common/pkg/umask go.podman.io/common/pkg/util go.podman.io/common/pkg/version go.podman.io/common/version -# go.podman.io/image/v5 v5.39.3-0.20260423135811-cbaa5f41e643 +# go.podman.io/image/v5 v5.39.3-0.20260423135811-cbaa5f41e643 => github.com/jankaluza/container-libs/image/v5 v5.0.0-20260428081533-0b40258c6c4e ## explicit; go 1.25.6 go.podman.io/image/v5/copy go.podman.io/image/v5/directory @@ -578,7 +577,7 @@ go.podman.io/image/v5/transports go.podman.io/image/v5/transports/alltransports go.podman.io/image/v5/types go.podman.io/image/v5/version -# go.podman.io/storage v1.62.1-0.20260423135811-cbaa5f41e643 +# go.podman.io/storage v1.62.1-0.20260423135811-cbaa5f41e643 => github.com/jankaluza/container-libs/storage v0.0.0-20260428081533-0b40258c6c4e ## explicit; go 1.25.0 go.podman.io/storage go.podman.io/storage/drivers @@ -825,3 +824,6 @@ tags.cncf.io/container-device-interface/pkg/parser # tags.cncf.io/container-device-interface/specs-go v1.1.0 ## explicit; go 1.19 tags.cncf.io/container-device-interface/specs-go +# go.podman.io/storage => github.com/jankaluza/container-libs/storage v0.0.0-20260428081533-0b40258c6c4e +# go.podman.io/common => github.com/jankaluza/container-libs/common v0.0.0-20260428081533-0b40258c6c4e +# go.podman.io/image/v5 => github.com/jankaluza/container-libs/image/v5 v5.0.0-20260428081533-0b40258c6c4e