Add cdi-spec-dir option to top level options.

This commit adds new --cdi-spec-dir global option. This
option is used to add additional CDI spec paths.

Signed-off-by: Micah Chambers (eos) <mchambers@anduril.com>
Signed-off-by: Jan Kaluza <jkaluza@redhat.com>
This commit is contained in:
Micah Chambers (eos)
2024-01-30 15:48:39 -08:00
committed by Jan Kaluza
parent a36276f5ad
commit dce36131ae
11 changed files with 69 additions and 9 deletions

View File

@ -247,6 +247,9 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
if cmd.Flag("hooks-dir").Changed {
podmanConfig.ContainersConf.Engine.HooksDir.Set(podmanConfig.HooksDir)
}
if cmd.Flag("cdi-spec-dir").Changed {
podmanConfig.ContainersConf.Engine.CdiSpecDirs.Set(podmanConfig.CdiSpecDirs)
}
// Currently it is only possible to restore a container with the same runtime
// as used for checkpointing. It should be possible to make crun and runc
@ -566,6 +569,10 @@ func rootFlags(cmd *cobra.Command, podmanConfig *entities.PodmanConfig) {
pFlags.StringArrayVar(&podmanConfig.HooksDir, hooksDirFlagName, podmanConfig.ContainersConfDefaultsRO.Engine.HooksDir.Get(), "Set the OCI hooks directory path (may be set multiple times)")
_ = cmd.RegisterFlagCompletionFunc(hooksDirFlagName, completion.AutocompleteDefault)
cdiSpecDirFlagName := "cdi-spec-dir"
pFlags.StringArrayVar(&podmanConfig.CdiSpecDirs, cdiSpecDirFlagName, podmanConfig.ContainersConfDefaultsRO.Engine.CdiSpecDirs.Get(), "Set the CDI spec directory path (may be set multiple times)")
_ = cmd.RegisterFlagCompletionFunc(cdiSpecDirFlagName, completion.AutocompleteDefault)
pFlags.IntVar(&podmanConfig.MaxWorks, "max-workers", (runtime.NumCPU()*3)+1, "The maximum number of workers for parallel operations")
namespaceFlagName := "namespace"

View File

@ -25,6 +25,10 @@ man pages.
## GLOBAL OPTIONS
#### **--cdi-spec-dir**=*path*
The CDI spec directory path (may be set multiple times). Default path is `/etc/cdi`.
#### **--cgroup-manager**=*manager*
The CGroup manager to use for container cgroups. Supported values are __cgroupfs__ or __systemd__. Default is _systemd_ unless overridden in the containers.conf file.

View File

@ -639,6 +639,7 @@ func (c *Container) generateSpec(ctx context.Context) (s *spec.Spec, cleanupFunc
// Warning: CDI may alter g.Config in place.
if len(c.config.CDIDevices) > 0 {
registry, err := cdi.NewCache(
cdi.WithSpecDirs(c.runtime.config.Engine.CdiSpecDirs.Get()...),
cdi.WithAutoRefresh(false),
)
if err != nil {

View File

@ -328,6 +328,17 @@ func WithCDI(devices []string) CtrCreateOption {
}
}
func WithCDISpecDirs(cdiSpecDirs []string) RuntimeOption {
return func(rt *Runtime) error {
if rt.valid {
return define.ErrRuntimeFinalized
}
rt.config.Engine.CdiSpecDirs.Set(cdiSpecDirs)
return nil
}
}
// WithStorageOpts sets the devices to check for CDI configuration.
func WithStorageOpts(storageOpts map[string]string) CtrCreateOption {
return func(ctr *Container) error {

View File

@ -35,6 +35,7 @@ type PodmanConfig struct {
CPUProfile string // Hidden: Should CPU profile be taken
EngineMode EngineMode // ABI or Tunneling mode
HooksDir []string
CdiSpecDirs []string
Identity string // ssh identity for connecting to server
IsRenumber bool // Is this a system renumber command? If so, a number of checks will be relaxed
IsReset bool // Is this a system reset command? If so, a number of checks will be skipped/omitted

View File

@ -212,6 +212,10 @@ func getRuntime(ctx context.Context, fs *flag.FlagSet, opts *engineOpts) (*libpo
options = append(options, libpod.WithDatabaseBackend(cfg.ContainersConf.Engine.DBBackend))
}
if cfg.CdiSpecDirs != nil {
options = append(options, libpod.WithCDISpecDirs(cfg.CdiSpecDirs))
}
if cfg.Syslog {
options = append(options, libpod.WithSyslog())
}

View File

@ -9,6 +9,7 @@ import (
"path/filepath"
"strings"
"github.com/containers/common/pkg/config"
"github.com/opencontainers/runtime-tools/generate"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
@ -16,9 +17,10 @@ import (
)
// DevicesFromPath computes a list of devices
func DevicesFromPath(g *generate.Generator, devicePath string) error {
func DevicesFromPath(g *generate.Generator, devicePath string, config *config.Config) error {
if isCDIDevice(devicePath) {
registry, err := cdi.NewCache(
cdi.WithSpecDirs(config.Engine.CdiSpecDirs.Get()...),
cdi.WithAutoRefresh(false),
)
if err != nil {

View File

@ -24,9 +24,10 @@ import (
)
// DevicesFromPath computes a list of devices
func DevicesFromPath(g *generate.Generator, devicePath string) error {
func DevicesFromPath(g *generate.Generator, devicePath string, config *config.Config) error {
if isCDIDevice(devicePath) {
registry, err := cdi.NewCache(
cdi.WithSpecDirs(config.Engine.CdiSpecDirs.Get()...),
cdi.WithAutoRefresh(false),
)
if err != nil {

View File

@ -56,7 +56,7 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
if !s.IsPrivileged() {
// add default devices from containers.conf
for _, device := range rtc.Containers.Devices.Get() {
if err = DevicesFromPath(&g, device); err != nil {
if err = DevicesFromPath(&g, device, rtc); err != nil {
return nil, err
}
}
@ -67,7 +67,7 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
}
// add default devices specified by caller
for _, device := range userDevices {
if err = DevicesFromPath(&g, device.Path); err != nil {
if err = DevicesFromPath(&g, device.Path, rtc); err != nil {
return nil, err
}
}

View File

@ -256,7 +256,7 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
var userDevices []spec.LinuxDevice
// add default devices from containers.conf
for _, device := range rtc.Containers.Devices.Get() {
if err = DevicesFromPath(&g, device); err != nil {
if err = DevicesFromPath(&g, device, rtc); err != nil {
return nil, err
}
}
@ -267,7 +267,7 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
}
// add default devices specified by caller
for _, device := range userDevices {
if err = DevicesFromPath(&g, device.Path); err != nil {
if err = DevicesFromPath(&g, device.Path, rtc); err != nil {
return nil, err
}
}

View File

@ -3,19 +3,29 @@
package integration
import (
"errors"
"fmt"
"io/fs"
"os"
"os/exec"
"path/filepath"
"strings"
. "github.com/containers/podman/v5/test/utils"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
func createContainersConfFileWithDevices(pTest *PodmanTestIntegration, devices string) {
func createContainersConfFileWithDevices(pTest *PodmanTestIntegration, devices string, cdiSpecDirs []string) {
configPath := filepath.Join(pTest.TempDir, "containers.conf")
containersConf := []byte(fmt.Sprintf("[containers]\ndevices = [%s]\n", devices))
if len(cdiSpecDirs) > 0 {
quoted := make([]string, len(cdiSpecDirs))
for i, dir := range cdiSpecDirs {
quoted[i] = fmt.Sprintf("%q", dir)
}
containersConf = append(containersConf, []byte(fmt.Sprintf("[engine]\ncdi_spec_dirs = [%s]\n", strings.Join(quoted, ", ")))...)
}
err := os.WriteFile(configPath, containersConf, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
@ -103,7 +113,7 @@ var _ = Describe("Podman run device", func() {
It("podman run CDI device test", func() {
SkipIfRootless("Rootless will not be able to create files/folders in /etc")
cdiDir := "/etc/cdi"
if _, err := os.Stat(cdiDir); os.IsNotExist(err) {
if _, err := os.Stat(cdiDir); errors.Is(err, fs.ErrNotExist) {
Expect(os.MkdirAll(cdiDir, os.ModePerm)).To(Succeed())
}
defer os.RemoveAll(cdiDir)
@ -116,7 +126,26 @@ var _ = Describe("Podman run device", func() {
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
createContainersConfFileWithDevices(podmanTest, "\"vendor.com/device=myKmsg\"")
createContainersConfFileWithDevices(podmanTest, "\"vendor.com/device=myKmsg\"", []string{})
session = podmanTest.Podman([]string{"run", "-q", "--security-opt", "label=disable", ALPINE, "test", "-c", "/dev/kmsg1"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
})
It("podman run CDI device test with --cdi-spec-dir", func() {
SkipIfRemote("The --cdi-spec-dir only works locally.")
cdiDir := podmanTest.TempDir + "/cdi"
Expect(os.MkdirAll(cdiDir, os.ModePerm)).To(Succeed())
cmd := exec.Command("cp", "cdi/device.json", cdiDir)
err = cmd.Run()
Expect(err).ToNot(HaveOccurred())
session := podmanTest.Podman([]string{"run", "--cdi-spec-dir", cdiDir, "-q", "--security-opt", "label=disable", "--device", "vendor.com/device=myKmsg", ALPINE, "test", "-c", "/dev/kmsg1"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
createContainersConfFileWithDevices(podmanTest, "\"vendor.com/device=myKmsg\"", []string{cdiDir})
session = podmanTest.Podman([]string{"run", "-q", "--security-opt", "label=disable", ALPINE, "test", "-c", "/dev/kmsg1"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())