automation-tests/common/pkg/config/config.go

1231 lines
46 KiB
Go

package config
import (
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"
"slices"
"strings"
"github.com/containers/common/internal/attributedstring"
"github.com/containers/common/libnetwork/types"
"github.com/containers/storage/pkg/fileutils"
"github.com/containers/storage/pkg/homedir"
"github.com/containers/storage/pkg/unshare"
units "github.com/docker/go-units"
selinux "github.com/opencontainers/selinux/go-selinux"
"github.com/sirupsen/logrus"
)
const (
// UserOverrideContainersConfig holds the containers config path overridden by the rootless user
UserOverrideContainersConfig = ".config/" + _configPath
// Token prefix for looking for helper binary under $BINDIR
bindirPrefix = "$BINDIR"
)
var validImageVolumeModes = []string{"anonymous", "tmpfs", "ignore"}
// ProxyEnv is a list of Proxy Environment variables
var ProxyEnv = []string{
"http_proxy",
"https_proxy",
"ftp_proxy",
"no_proxy",
"HTTP_PROXY",
"HTTPS_PROXY",
"FTP_PROXY",
"NO_PROXY",
}
// Config contains configuration options for container tools
type Config struct {
// Containers specify settings that configure how containers will run ont the system
Containers ContainersConfig `toml:"containers"`
// Engine specifies how the container engine based on Engine will run
Engine EngineConfig `toml:"engine"`
// Machine specifies configurations of podman machine VMs
Machine MachineConfig `toml:"machine"`
// Network section defines the configuration of CNI Plugins
Network NetworkConfig `toml:"network"`
// Secret section defines configurations for the secret management
Secrets SecretConfig `toml:"secrets"`
// ConfigMap section defines configurations for the configmaps management
ConfigMaps ConfigMapConfig `toml:"configmaps"`
// Farms defines configurations for the buildfarm farms
Farms FarmConfig `toml:"farms"`
// Podmansh defined configurations for the podman shell
Podmansh PodmanshConfig `toml:"podmansh"`
loadedModules []string // only used at runtime to store which modules were loaded
}
// ContainersConfig represents the "containers" TOML config table
// containers global options for containers tools
type ContainersConfig struct {
// Devices to add to all containers
Devices attributedstring.Slice `toml:"devices,omitempty"`
// Volumes to add to all containers
Volumes attributedstring.Slice `toml:"volumes,omitempty"`
// ApparmorProfile is the apparmor profile name which is used as the
// default for the runtime.
ApparmorProfile string `toml:"apparmor_profile,omitempty"`
// Annotation to add to all containers
Annotations attributedstring.Slice `toml:"annotations,omitempty"`
// BaseHostsFile is the path to a hosts file, the entries from this file
// are added to the containers hosts file. As special value "image" is
// allowed which uses the /etc/hosts file from within the image and "none"
// which uses no base file at all. If it is empty we should default
// to /etc/hosts.
BaseHostsFile string `toml:"base_hosts_file,omitempty"`
// Default way to create a cgroup namespace for the container
CgroupNS string `toml:"cgroupns,omitempty"`
// Default cgroup configuration
Cgroups string `toml:"cgroups,omitempty"`
// CgroupConf entries specifies a list of cgroup files to write to and their values. For example
// "memory.high=1073741824" sets the memory.high limit to 1GB.
CgroupConf attributedstring.Slice `toml:"cgroup_conf,omitempty"`
// When no hostname is set for a container, use the container's name, with
// characters not valid for a hostname removed, as the hostname instead of
// the first 12 characters of the container's ID. Containers not running
// in a private UTS namespace will have their hostname set to the host's
// hostname regardless of this setting.
ContainerNameAsHostName bool `toml:"container_name_as_hostname,omitempty"`
// Capabilities to add to all containers.
DefaultCapabilities attributedstring.Slice `toml:"default_capabilities,omitempty"`
// Sysctls to add to all containers.
DefaultSysctls attributedstring.Slice `toml:"default_sysctls,omitempty"`
// DefaultUlimits specifies the default ulimits to apply to containers
DefaultUlimits attributedstring.Slice `toml:"default_ulimits,omitempty"`
// DefaultMountsFile is the path to the default mounts file for testing
DefaultMountsFile string `toml:"-"`
// DNSServers set default DNS servers.
DNSServers attributedstring.Slice `toml:"dns_servers,omitempty"`
// DNSOptions set default DNS options.
DNSOptions attributedstring.Slice `toml:"dns_options,omitempty"`
// DNSSearches set default DNS search domains.
DNSSearches attributedstring.Slice `toml:"dns_searches,omitempty"`
// EnableKeyring tells the container engines whether to create
// a kernel keyring for use within the container
EnableKeyring bool `toml:"keyring,omitempty"`
// EnableLabeling tells the container engines whether to use MAC
// Labeling to separate containers (SELinux)
EnableLabeling bool `toml:"label,omitempty"`
// EnableLabeledUsers indicates whether to enforce confined users with
// containers on SELinux systems. This option causes containers to
// maintain the current user and role field of the calling process.
// Otherwise containers run with user system_u, and the role system_r.
EnableLabeledUsers bool `toml:"label_users,omitempty"`
// Env is the environment variable list for container process.
Env attributedstring.Slice `toml:"env,omitempty"`
// EnvHost Pass all host environment variables into the container.
EnvHost bool `toml:"env_host,omitempty"`
// HostContainersInternalIP is used to set a specific host.containers.internal ip.
HostContainersInternalIP string `toml:"host_containers_internal_ip,omitempty"`
// HTTPProxy is the proxy environment variable list to apply to container process
HTTPProxy bool `toml:"http_proxy,omitempty"`
// Init tells container runtimes whether to run init inside the
// container that forwards signals and reaps processes.
Init bool `toml:"init,omitempty"`
// InitPath is the path for init to run if the Init bool is enabled
//
// Deprecated: Do not use this field directly use conf.FindInitBinary() instead.
InitPath string `toml:"init_path,omitempty"`
// InterfaceName tells container runtimes how to set interface names
// inside containers.
// The only valid value at the moment is "device" that indicates the
// interface name should be set as the network_interface name from
// the network config.
InterfaceName string `toml:"interface_name,omitempty"`
// IPCNS way to create a ipc namespace for the container
IPCNS string `toml:"ipcns,omitempty"`
// LogDriver for the container. For example: k8s-file and journald
LogDriver string `toml:"log_driver,omitempty"`
// LogSizeMax is the maximum number of bytes after which the log file
// will be truncated. It can be expressed as a human-friendly string
// that is parsed to bytes.
// Negative values indicate that the log file won't be truncated.
LogSizeMax int64 `toml:"log_size_max,omitempty,omitzero"`
// Specifies default format tag for container log messages.
// This is useful for creating a specific tag for container log messages.
// Containers logs default to truncated container ID as a tag.
LogTag string `toml:"log_tag,omitempty"`
// Mount to add to all containers
Mounts attributedstring.Slice `toml:"mounts,omitempty"`
// NetNS indicates how to create a network namespace for the container
NetNS string `toml:"netns,omitempty"`
// NoHosts tells container engine whether to create its own /etc/hosts
NoHosts bool `toml:"no_hosts,omitempty"`
// OOMScoreAdj tunes the host's OOM preferences for containers
// (accepts values from -1000 to 1000).
OOMScoreAdj *int `toml:"oom_score_adj,omitempty"`
// PidsLimit is the number of processes each container is restricted to
// by the cgroup process number controller.
PidsLimit int64 `toml:"pids_limit,omitempty,omitzero"`
// PidNS indicates how to create a pid namespace for the container
PidNS string `toml:"pidns,omitempty"`
// Copy the content from the underlying image into the newly created
// volume when the container is created instead of when it is started.
// If false, the container engine will not copy the content until
// the container is started. Setting it to true may have negative
// performance implications.
PrepareVolumeOnCreate bool `toml:"prepare_volume_on_create,omitempty"`
// Give extended privileges to all containers. A privileged container
// turns off the security features that isolate the container from the
// host. Dropped Capabilities, limited devices, read-only mount points,
// Apparmor/SELinux separation, and Seccomp filters are all disabled.
// Due to the disabled security features the privileged field should
// almost never be set as containers can easily break out of
// confinment.
//
// Containers running in a user namespace (e.g., rootless containers)
// cannot have more privileges than the user that launched them.
Privileged bool `toml:"privileged,omitempty"`
// ReadOnly causes engine to run all containers with root file system mounted read-only
ReadOnly bool `toml:"read_only,omitempty"`
// SeccompProfile is the seccomp.json profile path which is used as the
// default for the runtime.
SeccompProfile string `toml:"seccomp_profile,omitempty"`
// ShmSize holds the size of /dev/shm.
ShmSize string `toml:"shm_size,omitempty"`
// TZ sets the timezone inside the container
TZ string `toml:"tz,omitempty"`
// Umask is the umask inside the container.
Umask string `toml:"umask,omitempty"`
// UTSNS indicates how to create a UTS namespace for the container
UTSNS string `toml:"utsns,omitempty"`
// UserNS indicates how to create a User namespace for the container
UserNS string `toml:"userns,omitempty"`
// UserNSSize how many UIDs to allocate for automatically created UserNS
// Deprecated: no user of this field is known.
UserNSSize int `toml:"userns_size,omitempty,omitzero"`
}
// EngineConfig contains configuration options used to set up a engine runtime
type EngineConfig struct {
// CgroupCheck indicates the configuration has been rewritten after an
// upgrade to Fedora 31 to change the default OCI runtime for cgroupv2v2.
CgroupCheck bool `toml:"cgroup_check,omitempty"`
// CGroupManager is the CGroup Manager to use Valid values are "cgroupfs"
// and "systemd".
CgroupManager string `toml:"cgroup_manager,omitempty"`
// ConmonEnvVars are environment variables to pass to the Conmon binary
// when it is launched.
ConmonEnvVars attributedstring.Slice `toml:"conmon_env_vars,omitempty"`
// ConmonPath is the path to the Conmon binary used for managing containers.
// The first path pointing to a valid file will be used.
ConmonPath attributedstring.Slice `toml:"conmon_path,omitempty"`
// ConmonRsPath is the path to the Conmon-rs binary used for managing containers.
// The first path pointing to a valid file will be used.
ConmonRsPath attributedstring.Slice `toml:"conmonrs_path,omitempty"`
// CompatAPIEnforceDockerHub enforces using docker.io for completing
// short names in Podman's compatibility REST API. Note that this will
// ignore unqualified-search-registries and short-name aliases defined
// in containers-registries.conf(5).
CompatAPIEnforceDockerHub bool `toml:"compat_api_enforce_docker_hub,omitempty"`
// ComposeProviders specifies one or more external providers for the
// compose command. The first found provider is used for execution.
// Can be an absolute and relative path or a (file) name. Make sure to
// expand the return items via `os.ExpandEnv`.
ComposeProviders attributedstring.Slice `toml:"compose_providers,omitempty"`
// ComposeWarningLogs emits logs on each invocation of the compose
// command indicating that an external compose provider is being
// executed.
ComposeWarningLogs bool `toml:"compose_warning_logs,omitempty"`
// DBBackend is the database backend to be used by Podman.
DBBackend string `toml:"database_backend,omitempty"`
// DetachKeys is the sequence of keys used to detach a container.
DetachKeys string `toml:"detach_keys,omitempty"`
// EnablePortReservation determines whether engine will reserve ports on the
// host when they are forwarded to containers. When enabled, when ports are
// forwarded to containers, they are held open by conmon as long as the
// container is running, ensuring that they cannot be reused by other
// programs on the host. However, this can cause significant memory usage if
// a container has many ports forwarded to it. Disabling this can save
// memory.
EnablePortReservation bool `toml:"enable_port_reservation,omitempty"`
// Environment variables to be used when running the container engine (e.g., Podman, Buildah). For example "http_proxy=internal.proxy.company.com"
Env attributedstring.Slice `toml:"env,omitempty"`
// EventsLogFilePath is where the events log is stored.
EventsLogFilePath string `toml:"events_logfile_path,omitempty"`
// EventsLogFileMaxSize sets the maximum size for the events log. When the limit is exceeded,
// the logfile is rotated and the old one is deleted.
EventsLogFileMaxSize eventsLogMaxSize `toml:"events_logfile_max_size,omitzero"`
// EventsLogger determines where events should be logged.
EventsLogger string `toml:"events_logger,omitempty"`
// EventsContainerCreateInspectData creates a more verbose
// container-create event which includes a JSON payload with detailed
// information about the container.
EventsContainerCreateInspectData bool `toml:"events_container_create_inspect_data,omitempty"`
// graphRoot internal stores the location of the graphroot
graphRoot string
// HealthcheckEvents is set to indicate whenever podman should log healthcheck events.
// With many running healthcheck on short interval Podman will spam the event log a lot.
// Because this event is optional and only useful to external consumers that may want to
// know when a healthcheck is run or failed allow users to turn it off by setting it to false.
// Default is true.
HealthcheckEvents bool `toml:"healthcheck_events,omitempty"`
// HelperBinariesDir is a list of directories which are used to search for
// helper binaries.
HelperBinariesDir attributedstring.Slice `toml:"helper_binaries_dir,omitempty"`
// configuration files. When the same filename is present in
// multiple directories, the file in the directory listed last in
// this slice takes precedence.
HooksDir attributedstring.Slice `toml:"hooks_dir,omitempty"`
// Location of CDI configuration files. These define mounts devices and
// other configs according to the CDI spec. In particular this is used
// for GPU passthrough.
CdiSpecDirs attributedstring.Slice `toml:"cdi_spec_dirs,omitempty"`
// ImageBuildFormat (DEPRECATED) indicates the default image format to
// building container images. Should use ImageDefaultFormat
ImageBuildFormat string `toml:"image_build_format,omitempty"`
// ImageDefaultTransport is the default transport method used to fetch
// images.
ImageDefaultTransport string `toml:"image_default_transport,omitempty"`
// ImageParallelCopies indicates the maximum number of image layers
// to be copied simultaneously. If this is zero, container engines
// will fall back to containers/image defaults.
ImageParallelCopies uint `toml:"image_parallel_copies,omitempty,omitzero"`
// ImageDefaultFormat specified the manifest Type (oci, v2s2, or v2s1)
// to use when pulling, pushing, building container images. By default
// image pulled and pushed match the format of the source image.
// Building/committing defaults to OCI.
ImageDefaultFormat string `toml:"image_default_format,omitempty"`
// ImageVolumeMode Tells container engines how to handle the built-in
// image volumes. Acceptable values are "bind", "tmpfs", and "ignore".
ImageVolumeMode string `toml:"image_volume_mode,omitempty"`
// InfraCommand is the command run to start up a pod infra container.
InfraCommand string `toml:"infra_command,omitempty"`
// InfraImage is the image a pod infra container will use to manage
// namespaces.
InfraImage string `toml:"infra_image,omitempty"`
// InitPath is the path to the container-init binary.
//
// Deprecated: Do not use this field directly use conf.FindInitBinary() instead.
InitPath string `toml:"init_path,omitempty"`
// KubeGenerateType sets the Kubernetes kind/specification to generate by default
// with the podman kube generate command
KubeGenerateType string `toml:"kube_generate_type,omitempty"`
// LockType is the type of locking to use.
LockType string `toml:"lock_type,omitempty"`
// MultiImageArchive - if true, the container engine allows for storing
// archives (e.g., of the docker-archive transport) with multiple
// images. By default, Podman creates single-image archives.
MultiImageArchive bool `toml:"multi_image_archive,omitempty"`
// Namespace is the engine namespace to use. Namespaces are used to create
// scopes to separate containers and pods in the state. When namespace is
// set, engine will only view containers and pods in the same namespace. All
// containers and pods created will default to the namespace set here. A
// namespace of "", the empty string, is equivalent to no namespace, and all
// containers and pods will be visible. The default namespace is "".
Namespace string `toml:"namespace,omitempty"`
// NetworkCmdPath is the path to the slirp4netns binary.
NetworkCmdPath string `toml:"network_cmd_path,omitempty"`
// NetworkCmdOptions is the default options to pass to the slirp4netns binary.
// For example "allow_host_loopback=true"
NetworkCmdOptions attributedstring.Slice `toml:"network_cmd_options,omitempty"`
// NoPivotRoot sets whether to set no-pivot-root in the OCI runtime.
NoPivotRoot bool `toml:"no_pivot_root,omitempty"`
// NumLocks is the number of locks to make available for containers and
// pods.
NumLocks uint32 `toml:"num_locks,omitempty,omitzero"`
// OCIRuntime is the OCI runtime to use.
OCIRuntime string `toml:"runtime,omitempty"`
// OCIRuntimes are the set of configured OCI runtimes (default is runc).
OCIRuntimes map[string][]string `toml:"runtimes,omitempty"`
// PlatformToOCIRuntime requests specific OCI runtime for a specified platform of image.
PlatformToOCIRuntime map[string]string `toml:"platform_to_oci_runtime,omitempty"`
// PodExitPolicy determines the behaviour when the last container of a pod exits.
PodExitPolicy PodExitPolicy `toml:"pod_exit_policy,omitempty"`
// PullPolicy determines whether to pull image before creating or running a container
// default is "missing"
PullPolicy string `toml:"pull_policy,omitempty"`
// Indicates whether the application should be running in Remote mode
Remote bool `toml:"remote,omitempty"`
// Number of times to retry pulling/pushing images in case of failure
Retry uint `toml:"retry,omitempty"`
// Delay between retries in case pulling/pushing image fails
// If set, container engines will retry at the set interval,
// otherwise they delay 2 seconds and then exponentially back off.
RetryDelay string `toml:"retry_delay,omitempty"`
// RemoteURI is deprecated, see ActiveService
// RemoteURI containers connection information used to connect to remote system.
RemoteURI string `toml:"remote_uri,omitempty"`
// RemoteIdentity is deprecated, ServiceDestinations
// RemoteIdentity key file for RemoteURI
RemoteIdentity string `toml:"remote_identity,omitempty"`
// ActiveService index to Destinations added v2.0.3
ActiveService string `toml:"active_service,omitempty"`
// Add existing instances with requested compression algorithms to manifest list
AddCompression attributedstring.Slice `toml:"add_compression,omitempty"`
// ServiceDestinations mapped by service Names
ServiceDestinations map[string]Destination `toml:"service_destinations,omitempty"`
// SSHConfig contains the ssh config file path if not the default
SSHConfig string `toml:"ssh_config,omitempty"`
// RuntimePath is the path to OCI runtime binary for launching containers.
// The first path pointing to a valid file will be used This is used only
// when there are no OCIRuntime/OCIRuntimes defined. It is used only to be
// backward compatible with older versions of Podman.
RuntimePath attributedstring.Slice `toml:"runtime_path,omitempty"`
// RuntimeSupportsJSON is the list of the OCI runtimes that support
// --format=json.
RuntimeSupportsJSON attributedstring.Slice `toml:"runtime_supports_json,omitempty"`
// RuntimeSupportsNoCgroups is a list of OCI runtimes that support
// running containers without CGroups.
RuntimeSupportsNoCgroups attributedstring.Slice `toml:"runtime_supports_nocgroup,omitempty"`
// RuntimeSupportsKVM is a list of OCI runtimes that support
// KVM separation for containers.
RuntimeSupportsKVM attributedstring.Slice `toml:"runtime_supports_kvm,omitempty"`
// SetOptions contains a subset of config options. It's used to indicate if
// a given option has either been set by the user or by the parsed
// configuration file. If not, the corresponding option might be
// overwritten by values from the database. This behavior guarantees
// backwards compat with older version of libpod and Podman.
SetOptions
// SignaturePolicyPath is the path to a signature policy to use for
// validating images. If left empty, the containers/image default signature
// policy will be used.
SignaturePolicyPath string `toml:"-"`
// SDNotify tells container engine to allow containers to notify the host systemd of
// readiness using the SD_NOTIFY mechanism.
SDNotify bool `toml:"-"`
// ServiceTimeout is the number of seconds to wait without a connection
// before the `podman system service` times out and exits
ServiceTimeout uint `toml:"service_timeout,omitempty,omitzero"`
// StaticDir is the path to a persistent directory to store container
// files.
StaticDir string `toml:"static_dir,omitempty"`
// StopTimeout is the number of seconds to wait for container to exit
// before sending kill signal.
StopTimeout uint `toml:"stop_timeout,omitempty,omitzero"`
// ExitCommandDelay is the number of seconds to wait for the exit
// command to be send to the API process on the server.
ExitCommandDelay uint `toml:"exit_command_delay,omitempty,omitzero"`
// ImageCopyTmpDir is the default location for storing temporary
// container image content, Can be overridden with the TMPDIR
// environment variable. If you specify "storage", then the
// location of the container/storage tmp directory will be used.
ImageCopyTmpDir string `toml:"image_copy_tmp_dir,omitempty"`
// TmpDir is the path to a temporary directory to store per-boot container
// files. Must be stored in a tmpfs.
TmpDir string `toml:"tmp_dir,omitempty"`
// VolumePath is the default location that named volumes will be created
// under. This convention is followed by the default volume driver, but
// may not be by other drivers.
VolumePath string `toml:"volume_path,omitempty"`
// VolumePluginTimeout sets the default timeout, in seconds, for
// operations that must contact a volume plugin. Plugins are external
// programs accessed via REST API; this sets a timeout for requests to
// that API.
// A value of 0 is treated as no timeout.
VolumePluginTimeout uint `toml:"volume_plugin_timeout,omitempty,omitzero"`
// VolumePlugins is a set of plugins that can be used as the backend for
// Podman named volumes. Each volume is specified as a name (what Podman
// will refer to the plugin as) mapped to a path, which must point to a
// Unix socket that conforms to the Volume Plugin specification.
VolumePlugins map[string]string `toml:"volume_plugins,omitempty"`
// ChownCopiedFiles tells the container engine whether to chown files copied
// into a container to the container's primary uid/gid.
ChownCopiedFiles bool `toml:"chown_copied_files,omitempty"`
// CompressionFormat is the compression format used to compress image layers.
CompressionFormat string `toml:"compression_format,omitempty"`
// CompressionLevel is the compression level used to compress image layers.
CompressionLevel *int `toml:"compression_level,omitempty"`
// PodmanshTimeout is the number of seconds to wait for podmansh logins.
// In other words, the timeout for the `podmansh` container to be in running
// state.
// Deprecated: Use podmansh.Timeout instead. podmansh.Timeout has precedence.
PodmanshTimeout uint `toml:"podmansh_timeout,omitempty,omitzero"`
}
// SetOptions contains a subset of options in a Config. It's used to indicate if
// a given option has either been set by the user or by a parsed engine
// configuration file. If not, the corresponding option might be overwritten by
// values from the database. This behavior guarantees backwards compat with
// older version of libpod and Podman.
type SetOptions struct {
// StorageConfigRunRootSet indicates if the RunRoot has been explicitly set
// by the config or by the user. It's required to guarantee backwards
// compatibility with older versions of libpod for which we must query the
// database configuration. Not included in the on-disk config.
StorageConfigRunRootSet bool `toml:"-"`
// StorageConfigGraphRootSet indicates if the RunRoot has been explicitly
// set by the config or by the user. It's required to guarantee backwards
// compatibility with older versions of libpod for which we must query the
// database configuration. Not included in the on-disk config.
StorageConfigGraphRootSet bool `toml:"-"`
// StorageConfigGraphDriverNameSet indicates if the GraphDriverName has been
// explicitly set by the config or by the user. It's required to guarantee
// backwards compatibility with older versions of libpod for which we must
// query the database configuration. Not included in the on-disk config.
StorageConfigGraphDriverNameSet bool `toml:"-"`
}
// NetworkConfig represents the "network" TOML config table
type NetworkConfig struct {
// NetworkBackend determines what backend should be used for Podman's
// networking.
NetworkBackend string `toml:"network_backend,omitempty"`
// CNIPluginDirs is where CNI plugin binaries are stored.
CNIPluginDirs attributedstring.Slice `toml:"cni_plugin_dirs,omitempty"`
// NetavarkPluginDirs is a list of directories which contain netavark plugins.
NetavarkPluginDirs attributedstring.Slice `toml:"netavark_plugin_dirs,omitempty"`
// FirewallDriver is the firewall driver to be used
FirewallDriver string `toml:"firewall_driver,omitempty"`
// DefaultNetwork is the network name of the default network
// to attach pods to.
DefaultNetwork string `toml:"default_network,omitempty"`
// DefaultSubnet is the subnet to be used for the default network.
// If a network with the name given in DefaultNetwork is not present
// then a new network using this subnet will be created.
// Must be a valid IPv4 CIDR block.
DefaultSubnet string `toml:"default_subnet,omitempty"`
// DefaultSubnetPools is a list of subnets and size which are used to
// allocate subnets automatically for podman network create.
// It will iterate through the list and will pick the first free subnet
// with the given size. This is only used for ipv4 subnets, ipv6 subnets
// are always assigned randomly.
DefaultSubnetPools []SubnetPool `toml:"default_subnet_pools,omitempty"`
// DefaultRootlessNetworkCmd is used to set the default rootless network
// program, either "slirp4nents" (default) or "pasta".
DefaultRootlessNetworkCmd string `toml:"default_rootless_network_cmd,omitempty"`
// NetworkConfigDir is where network configuration files are stored.
NetworkConfigDir string `toml:"network_config_dir,omitempty"`
// DNSBindPort is the port that should be used by dns forwarding daemon
// for netavark rootful bridges with dns enabled. This can be necessary
// when other dns forwarders run on the machine. 53 is used if unset.
DNSBindPort uint16 `toml:"dns_bind_port,omitempty,omitzero"`
// PastaOptions contains a default list of pasta(1) options that should
// be used when running pasta.
PastaOptions attributedstring.Slice `toml:"pasta_options,omitempty"`
}
type SubnetPool struct {
// Base is a bigger subnet which will be used to allocate a subnet with
// the given size.
Base *types.IPNet `toml:"base,omitempty"`
// Size is the CIDR for the new subnet. It must be equal or small
// than the CIDR from the base subnet.
Size int `toml:"size,omitempty"`
}
// SecretConfig represents the "secret" TOML config table
type SecretConfig struct {
// Driver specifies the secret driver to use.
// Current valid value:
// * file
// * pass
Driver string `toml:"driver,omitempty"`
// Opts contains driver specific options
Opts map[string]string `toml:"opts,omitempty"`
}
// ConfigMapConfig represents the "configmap" TOML config table
//
// revive does not like the name because the package is already called config
//
//nolint:revive
type ConfigMapConfig struct {
// Driver specifies the configmap driver to use.
// Current valid value:
// * file
// * pass
Driver string `toml:"driver,omitempty"`
// Opts contains driver specific options
Opts map[string]string `toml:"opts,omitempty"`
}
// MachineConfig represents the "machine" TOML config table
type MachineConfig struct {
// Number of CPU's a machine is created with.
CPUs uint64 `toml:"cpus,omitempty,omitzero"`
// DiskSize is the size of the disk in GB created when init-ing a podman-machine VM
DiskSize uint64 `toml:"disk_size,omitempty,omitzero"`
// Image is the image used when init-ing a podman-machine VM
Image string `toml:"image,omitempty"`
// Memory in MB a machine is created with.
Memory uint64 `toml:"memory,omitempty,omitzero"`
// User to use for rootless podman when init-ing a podman machine VM
User string `toml:"user,omitempty"`
// Volumes are host directories mounted into the VM by default.
Volumes attributedstring.Slice `toml:"volumes,omitempty"`
// Provider is the virtualization provider used to run podman-machine VM
Provider string `toml:"provider,omitempty"`
// Rosetta is the flag to enable Rosetta in the podman-machine VM on Apple Silicon
Rosetta bool `toml:"rosetta,omitempty"`
}
// FarmConfig represents the "farm" TOML config tables
type FarmConfig struct {
// Default is the default farm to be used when farming out builds
Default string `json:",omitempty" toml:"default,omitempty"`
// List is a map of farms created where key=farm-name and value=list of connections
List map[string][]string `json:",omitempty" toml:"list,omitempty"`
}
// Destination represents destination for remote service
type Destination struct {
// URI, required. Example: ssh://root@example.com:22/run/podman/podman.sock
URI string `toml:"uri"`
// Identity file with ssh key, optional
Identity string `json:",omitempty" toml:"identity,omitempty"`
// isMachine describes if the remote destination is a machine.
IsMachine bool `json:",omitempty" toml:"is_machine,omitempty"`
}
// PodmanshConfig represents configuration for the podman shell
type PodmanshConfig struct {
// Shell to start in container, default: "/bin/sh"
Shell string `toml:"shell,omitempty"`
// Name of the container the podmansh user should join
Container string `toml:"container,omitempty"`
// Timeout is the number of seconds to wait for podmansh logins.
// In other words, the timeout for the `podmansh` container to be in running
// state.
Timeout uint `toml:"timeout,omitempty,omitzero"`
}
// Consumes container image's os and arch and returns if any dedicated runtime was
// configured otherwise returns default runtime.
func (c *EngineConfig) ImagePlatformToRuntime(os string, arch string) string {
platformString := os + "/" + arch
if val, ok := c.PlatformToOCIRuntime[platformString]; ok {
return val
}
return c.OCIRuntime
}
// CheckCgroupsAndAdjustConfig checks if we're running rootless with the systemd
// cgroup manager. In case the user session isn't available, we're switching the
// cgroup manager to cgroupfs. Note, this only applies to rootless.
func (c *Config) CheckCgroupsAndAdjustConfig() {
if !unshare.IsRootless() || c.Engine.CgroupManager != SystemdCgroupsManager {
return
}
hasSession := false
session, found := os.LookupEnv("DBUS_SESSION_BUS_ADDRESS")
if !found {
xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR")
if xdgRuntimeDir == "" {
if dir, err := homedir.GetRuntimeDir(); err == nil {
xdgRuntimeDir = dir
}
}
sessionAddr := filepath.Join(xdgRuntimeDir, "bus")
if err := fileutils.Exists(sessionAddr); err == nil {
sessionAddr, err = filepath.EvalSymlinks(sessionAddr)
if err == nil {
os.Setenv("DBUS_SESSION_BUS_ADDRESS", "unix:path="+sessionAddr)
hasSession = true
}
}
} else {
for _, part := range strings.Split(session, ",") {
if strings.HasPrefix(part, "unix:path=") {
err := fileutils.Exists(strings.TrimPrefix(part, "unix:path="))
hasSession = err == nil
break
}
}
}
if !hasSession && unshare.GetRootlessUID() != 0 {
logrus.Warningf("The cgroupv2 manager is set to systemd but there is no systemd user session available")
logrus.Warningf("For using systemd, you may need to log in using a user session")
logrus.Warningf("Alternatively, you can enable lingering with: `loginctl enable-linger %d` (possibly as root)", unshare.GetRootlessUID())
logrus.Warningf("Falling back to --cgroup-manager=cgroupfs")
c.Engine.CgroupManager = CgroupfsCgroupsManager
}
}
func (c *Config) addCAPPrefix() {
caps := c.Containers.DefaultCapabilities.Get()
newCaps := make([]string, 0, len(caps))
for _, val := range caps {
if !strings.HasPrefix(strings.ToLower(val), "cap_") {
val = "CAP_" + strings.ToUpper(val)
}
newCaps = append(newCaps, val)
}
c.Containers.DefaultCapabilities.Set(newCaps)
}
// Validate is the main entry point for library configuration validation.
func (c *Config) Validate() error {
if err := c.Containers.Validate(); err != nil {
return fmt.Errorf("validating containers config: %w", err)
}
if !c.Containers.EnableLabeling {
selinux.SetDisabled()
}
if err := c.Engine.Validate(); err != nil {
return fmt.Errorf("validating engine configs: %w", err)
}
if err := c.Network.Validate(); err != nil {
return fmt.Errorf("validating network configs %w", err)
}
return nil
}
// URI returns the URI Path to the machine image
func (m *MachineConfig) URI() string {
uri := m.Image
for _, val := range []string{"$ARCH", "$arch"} {
uri = strings.Replace(uri, val, runtime.GOARCH, 1)
}
for _, val := range []string{"$OS", "$os"} {
uri = strings.Replace(uri, val, runtime.GOOS, 1)
}
return uri
}
func (c *EngineConfig) findRuntime() string {
// Search for crun first followed by runc, runj, kata, runsc, ocijail
for _, name := range []string{"crun", "runc", "runj", "kata", "runsc", "ocijail"} {
for _, v := range c.OCIRuntimes[name] {
if err := fileutils.Exists(v); err == nil {
return name
}
}
if path, err := exec.LookPath(name); err == nil {
logrus.Debugf("Found default OCI runtime %s path via PATH environment variable", path)
return name
}
}
return ""
}
// Validate is the main entry point for Engine configuration validation
// It returns an `error` on validation failure, otherwise
// `nil`.
func (c *EngineConfig) Validate() error {
if err := c.validatePaths(); err != nil {
return err
}
if err := ValidateImageVolumeMode(c.ImageVolumeMode); err != nil {
return err
}
// Check if the pullPolicy from containers.conf is valid
// if it is invalid returns the error
pullPolicy := strings.ToLower(c.PullPolicy)
if _, err := ValidatePullPolicy(pullPolicy); err != nil {
return fmt.Errorf("invalid pull type from containers.conf %q: %w", c.PullPolicy, err)
}
if _, err := ParseDBBackend(c.DBBackend); err != nil {
return err
}
return nil
}
// Validate is the main entry point for containers configuration validation
// It returns an `error` on validation failure, otherwise
// `nil`.
func (c *ContainersConfig) Validate() error {
if err := c.validateUlimits(); err != nil {
return err
}
if err := c.validateDevices(); err != nil {
return err
}
if err := c.validateInterfaceName(); err != nil {
return err
}
if err := c.validateTZ(); err != nil {
return err
}
if err := c.validateUmask(); err != nil {
return err
}
if c.LogSizeMax >= 0 && c.LogSizeMax < OCIBufSize {
return fmt.Errorf("log size max should be negative or >= %d", OCIBufSize)
}
if _, err := units.FromHumanSize(c.ShmSize); err != nil {
return fmt.Errorf("invalid --shm-size %s, %q", c.ShmSize, err)
}
return nil
}
// Validate is the main entry point for network configuration validation.
// The parameter `onExecution` specifies if the validation should include
// execution checks. It returns an `error` on validation failure, otherwise
// `nil`.
func (c *NetworkConfig) Validate() error {
if &c.DefaultSubnetPools != &DefaultSubnetPools {
for _, pool := range c.DefaultSubnetPools {
if pool.Base.IP.To4() == nil {
return fmt.Errorf("invalid subnet pool ip %q", pool.Base.IP)
}
ones, _ := pool.Base.IPNet.Mask.Size()
if ones > pool.Size {
return fmt.Errorf("invalid subnet pool, size is bigger than subnet %q", &pool.Base.IPNet)
}
if pool.Size > 32 {
return errors.New("invalid subnet pool size, must be between 0-32")
}
}
}
return nil
}
// FindConmon iterates over (*Config).ConmonPath and returns the path
// to first (version) matching conmon binary. If non is found, we try
// to do a path lookup of "conmon".
func (c *Config) FindConmon() (string, error) {
return findConmonPath(c.Engine.ConmonPath.Get(), "conmon")
}
func findConmonPath(paths []string, binaryName string) (string, error) {
for _, path := range paths {
stat, err := os.Stat(path)
if err != nil {
continue
}
if stat.IsDir() {
continue
}
logrus.Debugf("Using conmon: %q", path)
return path, nil
}
// Search the $PATH as last fallback
if path, err := exec.LookPath(binaryName); err == nil {
logrus.Debugf("Using conmon from $PATH: %q", path)
return path, nil
}
return "", fmt.Errorf("could not find a working conmon binary (configured options: %v: %w)",
paths, ErrInvalidArg)
}
// FindConmonRs iterates over (*Config).ConmonRsPath and returns the path
// to first (version) matching conmonrs binary. If non is found, we try
// to do a path lookup of "conmonrs".
func (c *Config) FindConmonRs() (string, error) {
return findConmonPath(c.Engine.ConmonRsPath.Get(), "conmonrs")
}
// GetDefaultEnv returns the environment variables for the container.
// It will check the HTTPProxy and HostEnv booleans and add the appropriate
// environment variables to the container.
func (c *Config) GetDefaultEnv() []string {
return c.GetDefaultEnvEx(c.Containers.EnvHost, c.Containers.HTTPProxy)
}
// GetDefaultEnvEx returns the environment variables for the container.
// It will check the HTTPProxy and HostEnv boolean parameters and return the appropriate
// environment variables for the container.
func (c *Config) GetDefaultEnvEx(envHost, httpProxy bool) []string {
var env []string
if envHost {
env = append(env, os.Environ()...)
} else if httpProxy {
for _, p := range ProxyEnv {
if val, ok := os.LookupEnv(p); ok {
env = append(env, fmt.Sprintf("%s=%s", p, val))
}
}
}
return append(env, c.Containers.Env.Get()...)
}
// Device parses device mapping string to a src, dest & permissions string
// Valid values for device looklike:
//
// '/dev/sdc"
// '/dev/sdc:/dev/xvdc"
// '/dev/sdc:/dev/xvdc:rwm"
// '/dev/sdc:rm"
func Device(device string) (src, dst, permissions string, err error) {
permissions = "rwm"
split := strings.Split(device, ":")
switch len(split) {
case 3:
if !IsValidDeviceMode(split[2]) {
return "", "", "", fmt.Errorf("invalid device mode: %s", split[2])
}
permissions = split[2]
fallthrough
case 2:
if IsValidDeviceMode(split[1]) {
permissions = split[1]
} else {
if split[1] == "" || split[1][0] != '/' {
return "", "", "", fmt.Errorf("invalid device mode: %s", split[1])
}
dst = split[1]
}
fallthrough
case 1:
if !strings.HasPrefix(split[0], "/dev/") {
return "", "", "", fmt.Errorf("invalid device mode: %s", split[0])
}
src = split[0]
default:
return "", "", "", fmt.Errorf("invalid device specification: %s", device)
}
if dst == "" {
dst = src
}
return src, dst, permissions, nil
}
// IsValidDeviceMode checks if the mode for device is valid or not.
// IsValid mode is a composition of r (read), w (write), and m (mknod).
func IsValidDeviceMode(mode string) bool {
legalDeviceMode := map[rune]bool{
'r': true,
'w': true,
'm': true,
}
if mode == "" {
return false
}
for _, c := range mode {
if !legalDeviceMode[c] {
return false
}
legalDeviceMode[c] = false
}
return true
}
// Reload clean the cached config and reloads the configuration from containers.conf files
// This function is meant to be used for long-running processes that need to reload potential changes made to
// the cached containers.conf files.
func Reload() (*Config, error) {
return New(&Options{SetDefault: true})
}
var (
bindirFailed = false
bindirCached = ""
)
func findBindir() string {
if bindirCached != "" || bindirFailed {
return bindirCached
}
execPath, err := os.Executable()
if err == nil {
// Resolve symbolic links to find the actual binary file path.
execPath, err = filepath.EvalSymlinks(execPath)
}
if err != nil {
// If failed to find executable (unlikely to happen), warn about it.
// The bindirFailed flag will track this, so we only warn once.
logrus.Warnf("Failed to find $BINDIR: %v", err)
bindirFailed = true
return ""
}
bindirCached = filepath.Dir(execPath)
return bindirCached
}
// FindHelperBinary will search the given binary name in the configured directories.
// If searchPATH is set to true it will also search in $PATH.
func (c *Config) FindHelperBinary(name string, searchPATH bool) (string, error) {
dirList := c.Engine.HelperBinariesDir.Get()
bindirPath := ""
bindirSearched := false
// If set, search this directory first. This is used in testing.
if dir, found := os.LookupEnv("CONTAINERS_HELPER_BINARY_DIR"); found {
dirList = append([]string{dir}, dirList...)
}
for _, path := range dirList {
if path == bindirPrefix || strings.HasPrefix(path, bindirPrefix+string(filepath.Separator)) {
// Calculate the path to the executable first time we encounter a $BINDIR prefix.
if !bindirSearched {
bindirSearched = true
bindirPath = findBindir()
}
// If there's an error, don't stop the search for the helper binary.
// findBindir() will have warned once during the first failure.
if bindirPath == "" {
continue
}
// Replace the $BINDIR prefix with the path to the directory of the current binary.
if path == bindirPrefix {
path = bindirPath
} else {
path = filepath.Join(bindirPath, strings.TrimPrefix(path, bindirPrefix+string(filepath.Separator)))
}
}
// Absolute path will force exec.LookPath to check for binary existence instead of lookup everywhere in PATH
if abspath, err := filepath.Abs(filepath.Join(path, name)); err == nil {
// exec.LookPath from absolute path on Unix is equal to os.Stat + IsNotDir + check for executable bits in FileMode
// exec.LookPath from absolute path on Windows is equal to os.Stat + IsNotDir for `file.ext` or loops through extensions from PATHEXT for `file`
if lp, err := exec.LookPath(abspath); err == nil {
return lp, nil
}
}
}
if searchPATH {
return exec.LookPath(name)
}
configHint := "To resolve this error, set the helper_binaries_dir key in the `[engine]` section of containers.conf to the directory containing your helper binaries."
if len(dirList) == 0 {
return "", fmt.Errorf("could not find %q because there are no helper binary directories configured. %s", name, configHint)
}
return "", fmt.Errorf("could not find %q in one of %v. %s", name, dirList, configHint)
}
// ImageCopyTmpDir default directory to store temporary image files during copy
func (c *Config) ImageCopyTmpDir() (string, error) {
if path, found := os.LookupEnv("TMPDIR"); found {
return path, nil
}
switch c.Engine.ImageCopyTmpDir {
case "":
return "", nil
case "storage":
return filepath.Join(c.Engine.graphRoot, "tmp"), nil
default:
if filepath.IsAbs(c.Engine.ImageCopyTmpDir) {
return c.Engine.ImageCopyTmpDir, nil
}
}
return "", fmt.Errorf("invalid image_copy_tmp_dir value %q (relative paths are not accepted)", c.Engine.ImageCopyTmpDir)
}
// setupEnv sets the environment variables for the engine
func (c *Config) setupEnv() error {
for _, env := range c.Engine.Env.Get() {
splitEnv := strings.SplitN(env, "=", 2)
if len(splitEnv) != 2 {
logrus.Warnf("invalid environment variable for engine %s, valid configuration is KEY=value pair", env)
continue
}
// skip if the env is already defined
if _, ok := os.LookupEnv(splitEnv[0]); ok {
logrus.Debugf("environment variable %s is already defined, skip the settings from containers.conf", splitEnv[0])
continue
}
if err := os.Setenv(splitEnv[0], splitEnv[1]); err != nil {
return err
}
}
return nil
}
// eventsLogMaxSize is the type used by EventsLogFileMaxSize
type eventsLogMaxSize uint64
// UnmarshalText parses the JSON encoding of eventsLogMaxSize and
// stores it in a value.
func (e *eventsLogMaxSize) UnmarshalText(text []byte) error {
// REMOVE once writing works
if string(text) == "" {
return nil
}
val, err := units.FromHumanSize((string(text)))
if err != nil {
return err
}
if val < 0 {
return fmt.Errorf("events log file max size cannot be negative: %s", string(text))
}
*e = eventsLogMaxSize(uint64(val))
return nil
}
// MarshalText returns the JSON encoding of eventsLogMaxSize.
func (e eventsLogMaxSize) MarshalText() ([]byte, error) {
if uint64(e) == DefaultEventsLogSizeMax || e == 0 {
v := []byte{}
return v, nil
}
return []byte(fmt.Sprintf("%d", e)), nil
}
func ValidateImageVolumeMode(mode string) error {
if mode == "" {
return nil
}
if slices.Contains(validImageVolumeModes, mode) {
return nil
}
return fmt.Errorf("invalid image volume mode %q required value: %s", mode, strings.Join(validImageVolumeModes, ", "))
}
// FindInitBinary will return the path to the init binary (catatonit)
func (c *Config) FindInitBinary() (string, error) {
// Sigh, for some reason we ended up with two InitPath field in containers.conf and
// both are used in podman so we have to keep supporting both to prevent regressions.
if c.Containers.InitPath != "" {
return c.Containers.InitPath, nil
}
if c.Engine.InitPath != "" {
return c.Engine.InitPath, nil
}
// keep old default working to guarantee backwards compat
if err := fileutils.Exists(DefaultInitPath); err == nil {
return DefaultInitPath, nil
}
return c.FindHelperBinary(defaultInitName, true)
}
// PodmanshTimeout returns the timeout in seconds for podmansh to connect to the container.
// Returns podmansh.Timeout if set, otherwise engine.PodmanshTimeout for backwards compatibility.
func (c *Config) PodmanshTimeout() uint {
// podmansh.Timeout has precedence, if set
if c.Podmansh.Timeout > 0 {
return c.Podmansh.Timeout
}
return c.Engine.PodmanshTimeout
}