/** # Copyright (c) 2024, HCUOpt CORPORATION. All rights reserved. **/ package config import ( "bufio" "dcu-container-toolkit/internal/logger" "dcu-container-toolkit/internal/lookup" "os" "path/filepath" "strings" "tags.cncf.io/container-device-interface/pkg/cdi" ) const ( configOverride = "XDG_CONFIG_HOME" configFilePath = "dcu-container-runtime/config.toml" dtkCTKExecutable = "dcu-ctk" dtkCTKDefaultFilePath = "/usr/bin/dcu-ctk" dtkCDIHookDefaultFilePath = "/usr/bin/dcu-cdi-hook" // dtkContainerRuntimeHookExecutable = "dcu-container-runtime-hook" // dtkContainerRuntimeHookDefaultPath = "/usr/bin/dcu-container-runtime-hook" ) var ( // DefaultExecutableDir specifies the default path to use for executables if they cannot be located in the path. DefaultExecutableDir = "/usr/bin" // DTKContainerRuntimeHookExecutable is the executable name for the DTK Container Runtime Hook DTKContainerRuntimeHookExecutable = "dcu-container-runtime-hook" // DTKContainerToolkitExecutable is the executable name for the DTK Container Toolkit (an alias for the DTK Container Runtime Hook) DTKContainerToolkitExecutable = "dcu-container-toolkit" ) // Config represents the contents of the config.toml file for the DTK Container Toolkit type Config struct { DisableRequire bool `toml:"disable-require"` SwarmResource string `toml:"swarm-resource"` AcceptEnvvarUnprivileged bool `toml:"accept-dtk-visible-devices-envvar-when-unprivileged"` AcceptDeviceListAsVolumeMounts bool `toml:"accept-dtk-visible-devices-as-volume-mounts"` // SupportedDriverCapabilities string `toml:"supported-driver-capabilities"` DTKCTKConfig CTKConfig `toml:"dcu-ctk"` DTKContainerRuntimeConfig RuntimeConfig `toml:"dcu-container-runtime"` } // GetConfigFilePath returns the path to the config file for the configured system func GetConfigFilePath() string { if XDGConfigDir := os.Getenv(configOverride); len(XDGConfigDir) != 0 { return filepath.Join(XDGConfigDir, configFilePath) } return filepath.Join("/etc", configFilePath) } // GetConfig sets up the config struct. Values are read from a toml file // or set via the environment. func GetConfig() (*Config, error) { cfg, err := New( WithConfigFile(GetConfigFilePath()), ) if err != nil { return nil, err } return cfg.Config() } // GetDefault defines the default values for the config func GetDefault() (*Config, error) { d := Config{ AcceptEnvvarUnprivileged: true, DTKCTKConfig: CTKConfig{ Path: dtkCTKExecutable, }, DTKContainerRuntimeConfig: RuntimeConfig{ DebugFilePath: "/dev/null", LogLevel: "info", Runtimes: []string{"docker-runc", "runc", "crun"}, Mode: "auto", Modes: modesConfig{ CSV: csvModeConfig{ MountSpecPath: "/etc/dcu-container-runtime/host-files-for-container.d", }, CDI: cdiModeConfig{ DefaultKind: "c-3000.com/hcu", AnnotationPrefixes: []string{cdi.AnnotationPrefix}, SpecDirs: cdi.DefaultSpecDirs, }, }, }, } return &d, nil } func GetUserGroup() string { if isSuse() { return "root:video" } return "" } // isSuse returns whether a SUSE-based distribution was detected. func isSuse() bool { suseDists := map[string]bool{ "suse": true, "opensuse": true, } idsLike := getDistIDLike() for _, id := range idsLike { if suseDists[id] { return true } } return false } // getDistIDLike returns the ID_LIKE field from /etc/os-release. // We can override this for testing. var getDistIDLike = func() []string { releaseFile, err := os.Open("/etc/os-release") if err != nil { return nil } defer releaseFile.Close() scanner := bufio.NewScanner(releaseFile) for scanner.Scan() { line := scanner.Text() if strings.HasPrefix(line, "ID_LIKE=") { value := strings.Trim(strings.TrimPrefix(line, "ID_LIKE="), "\"") return strings.Split(value, " ") } } return nil } // ResolveDTKCDIHookPath resolves the path to the dcu-cdi-hook binary. // This executable is used in hooks and needs to be an absolute path. // If the path is specified as an absolute path, it is used directly // without checking for existence of an executable at that path. func ResolveDTKCDIHookPath(logger logger.Interface, dtkCDIHookPath string) string { if filepath.Base(dtkCDIHookPath) == "dcu-ctk" { return resolveWithDefault( logger, "DTK Container Toolkit CLI", dtkCDIHookPath, dtkCTKDefaultFilePath, ) } return resolveWithDefault( logger, "DTK CDI Hook CLI", dtkCDIHookPath, dtkCDIHookDefaultFilePath, ) } // resolveWithDefault resolves the path to the specified binary. // If an absolute path is specified, it is used directly without searching for the binary. // If the binary cannot be found in the path, the specified default is used instead. func resolveWithDefault(logger logger.Interface, label string, path string, defaultPath string) string { if filepath.IsAbs(path) { logger.Debugf("Using specified %v path %v", label, path) return path } if path == "" { path = filepath.Base(defaultPath) } logger.Debugf("Locating %v as %v", label, path) lookup := lookup.NewExecutableLocator(logger, "") resolvedPath := defaultPath targets, err := lookup.Locate(path) if err != nil { logger.Warningf("Failed to locate %v: %v", path, err) } else { logger.Debugf("Found %v candidates: %v", path, targets) resolvedPath = targets[0] } logger.Debugf("Using %v path %v", label, resolvedPath) return resolvedPath }