Skip to content

Commit

Permalink
Merge pull request #1826 from Luap99/connections
Browse files Browse the repository at this point in the history
pkg/config: rework system connections and farm storage
  • Loading branch information
openshift-merge-bot[bot] committed Jan 30, 2024
2 parents 3310a75 + f4b8836 commit 4729992
Show file tree
Hide file tree
Showing 15 changed files with 663 additions and 409 deletions.
17 changes: 8 additions & 9 deletions docs/containers.conf.5.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ a TOML format that can be easily modified and versioned.

Container engines read the __/usr/share/containers/containers.conf__,
__/etc/containers/containers.conf__, and __/etc/containers/containers.conf.d/\*.conf__
files if they exist.
When running in rootless mode, they also read
__$HOME/.config/containers/containers.conf__ and
__$HOME/.config/containers/containers.conf.d/\*.conf__ files.
for global configuration that effects all users.
For user specific configuration it reads __\$XDG_CONFIG_HOME/containers/containers.conf__ and
__\$XDG_CONFIG_HOME/containers/containers.conf.d/\*.conf__ files. When `$XDG_CONFIG_HOME` is not set it falls back to using `$HOME/.config` instead.

Fields specified in containers conf override the default options, as well as
options in previously read containers.conf files.
Expand Down Expand Up @@ -42,13 +41,13 @@ instance, `CONTAINERS_CONF=/tmp/my_containers.conf`.

## MODULES
A module is a containers.conf file located directly in or a sub-directory of the following three directories:
- __$HOME/.config/containers/containers.conf.modules__
- __\$XDG_CONFIG_HOME/containers/containers.conf.modules__ or __\$HOME/.config/containers/containers.conf.modules__ if `$XDG_CONFIG_HOME` is not set.
- __/etc/containers/containers.conf.modules__
- __/usr/share/containers/containers.conf.modules__

Files in those locations are not loaded by default but only on-demand. They are loaded after all system and user configuration files but before `CONTAINERS_CONF_OVERRIDE` hence allowing for overriding system and user configs.

Modules are currently supported by podman(1). The `podman --module` flag allows for loading a module and can be specified multiple times. If the specified value is an absolute path, the config file will be loaded directly. Relative paths are resolved relative to the three module directories mentioned above and in the specified order such that modules in `$HOME` allow for overriding those in `/etc` and `/usr/share`. Modules in `$HOME` (or `$XDG_CONFIG_HOME` if specified) are only used for rootless users.
Modules are currently supported by podman(1). The `podman --module` flag allows for loading a module and can be specified multiple times. If the specified value is an absolute path, the config file will be loaded directly. Relative paths are resolved relative to the three module directories mentioned above and in the specified order such that modules in `$XDG_CONFIG_HOME/$HOME` allow for overriding those in `/etc` and `/usr/share`.

## APPENDING TO STRING ARRAYS

Expand Down Expand Up @@ -459,7 +458,7 @@ and "$graphroot/networks" as rootless.
**firewall_driver**=""

The firewall driver to be used by netavark.
The default is empty which means netavark will pick one accordingly. Current supported
The default is empty which means netavark will pick one accordingly. Current supported
drivers are "iptables", "none" (no firewall rules will be created) and "firewalld" (firewalld is
experimental at the moment and not recommend outside of testing). In the future we are
planning to add support for a "nftables" driver.
Expand Down Expand Up @@ -952,8 +951,8 @@ provide a default configuration. Administrators can override fields in this
file by creating __/etc/containers/containers.conf__ to specify their own
configuration. They may also drop `.conf` files in
__/etc/containers/containers.conf.d__ which will be loaded in alphanumeric order.
Rootless users can further override fields in the config by creating a config
file stored in the __$HOME/.config/containers/containers.conf__ file or __.conf__ files in __$HOME/.config/containers/containers.conf.d__.
For user specific configuration it reads __\$XDG_CONFIG_HOME/containers/containers.conf__ and
__\$XDG_CONFIG_HOME/containers/containers.conf.d/\*.conf__ files. When `$XDG_CONFIG_HOME` is not set it falls back to using `$HOME/.config` instead.

Fields specified in a containers.conf file override the default options, as
well as options in previously loaded containers.conf files.
Expand Down
86 changes: 4 additions & 82 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ import (
"runtime"
"strings"

"github.com/BurntSushi/toml"
"github.com/containers/common/internal/attributedstring"
"github.com/containers/common/libnetwork/types"
"github.com/containers/common/pkg/capabilities"
"github.com/containers/storage/pkg/ioutils"
"github.com/containers/storage/pkg/unshare"
units "github.com/docker/go-units"
selinux "github.com/opencontainers/selinux/go-selinux"
Expand Down Expand Up @@ -667,9 +665,9 @@ type MachineConfig struct {
// FarmConfig represents the "farm" TOML config tables
type FarmConfig struct {
// Default is the default farm to be used when farming out builds
Default string `toml:"default,omitempty"`
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 `toml:"list,omitempty"`
List map[string][]string `json:",omitempty" toml:"list,omitempty"`
}

// Destination represents destination for remote service
Expand All @@ -678,10 +676,10 @@ type Destination struct {
URI string `toml:"uri"`

// Identity file with ssh key, optional
Identity string `toml:"identity,omitempty"`
Identity string `json:",omitempty" toml:"identity,omitempty"`

// isMachine describes if the remote destination is a machine.
IsMachine bool `toml:"is_machine,omitempty"`
IsMachine bool `json:",omitempty" toml:"is_machine,omitempty"`
}

// Consumes container image's os and arch and returns if any dedicated runtime was
Expand Down Expand Up @@ -1008,82 +1006,6 @@ func IsValidDeviceMode(mode string) bool {
return true
}

func rootlessConfigPath() (string, error) {
if configHome := os.Getenv("XDG_CONFIG_HOME"); configHome != "" {
return filepath.Join(configHome, _configPath), nil
}
home, err := unshare.HomeDir()
if err != nil {
return "", err
}

return filepath.Join(home, UserOverrideContainersConfig), nil
}

func Path() string {
if path := os.Getenv("CONTAINERS_CONF"); path != "" {
return path
}
if unshare.IsRootless() {
if rpath, err := rootlessConfigPath(); err == nil {
return rpath
}
return "$HOME/" + UserOverrideContainersConfig
}
return OverrideContainersConfig
}

// ReadCustomConfig reads the custom config and only generates a config based on it
// If the custom config file does not exists, function will return an empty config
func ReadCustomConfig() (*Config, error) {
path, err := customConfigFile()
if err != nil {
return nil, err
}
newConfig := &Config{}
if _, err := os.Stat(path); err == nil {
if err := readConfigFromFile(path, newConfig); err != nil {
return nil, err
}
} else {
if !errors.Is(err, os.ErrNotExist) {
return nil, err
}
}
// Let's always initialize the farm list so it is never nil
if newConfig.Farms.List == nil {
newConfig.Farms.List = make(map[string][]string)
}
return newConfig, nil
}

// Write writes the configuration to the default file
func (c *Config) Write() error {
var err error
path, err := customConfigFile()
if err != nil {
return err
}
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
return err
}

opts := &ioutils.AtomicFileWriterOptions{ExplicitCommit: true}
configFile, err := ioutils.NewAtomicFileWriterWithOpts(path, 0o644, opts)
if err != nil {
return err
}
defer configFile.Close()

enc := toml.NewEncoder(configFile)
if err := enc.Encode(c); err != nil {
return err
}

// If no errors commit the changes to the config file
return configFile.Commit()
}

// 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.
Expand Down
16 changes: 0 additions & 16 deletions pkg/config/config_darwin.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package config

import (
"os"
)

const (
// OverrideContainersConfig holds the default config path overridden by the root user
OverrideContainersConfig = "/etc/" + _configPath
Expand All @@ -16,18 +12,6 @@ const (
DefaultSignaturePolicyPath = "/etc/containers/policy.json"
)

// podman remote clients on darwin cannot use unshare.isRootless() to determine the configuration file locations.
func customConfigFile() (string, error) {
if path, found := os.LookupEnv("CONTAINERS_CONF"); found {
return path, nil
}
return rootlessConfigPath()
}

func ifRootlessConfigPath() (string, error) {
return rootlessConfigPath()
}

var defaultHelperBinariesDir = []string{
// Relative to the binary directory
"$BINDIR/../libexec/podman",
Expand Down
16 changes: 0 additions & 16 deletions pkg/config/config_freebsd.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package config

import (
"os"
)

const (
// OverrideContainersConfig holds the default config path overridden by the root user
OverrideContainersConfig = "/usr/local/etc/" + _configPath
Expand All @@ -16,18 +12,6 @@ const (
DefaultSignaturePolicyPath = "/usr/local/etc/containers/policy.json"
)

// podman remote clients on freebsd cannot use unshare.isRootless() to determine the configuration file locations.
func customConfigFile() (string, error) {
if path, found := os.LookupEnv("CONTAINERS_CONF"); found {
return path, nil
}
return rootlessConfigPath()
}

func ifRootlessConfigPath() (string, error) {
return rootlessConfigPath()
}

var defaultHelperBinariesDir = []string{
"/usr/local/bin",
"/usr/local/libexec/podman",
Expand Down
28 changes: 0 additions & 28 deletions pkg/config/config_linux.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package config

import (
"os"

"github.com/containers/storage/pkg/unshare"
selinux "github.com/opencontainers/selinux/go-selinux"
)

Expand All @@ -23,31 +20,6 @@ func selinuxEnabled() bool {
return selinux.GetEnabled()
}

func customConfigFile() (string, error) {
if path, found := os.LookupEnv("CONTAINERS_CONF"); found {
return path, nil
}
if unshare.GetRootlessUID() > 0 {
path, err := rootlessConfigPath()
if err != nil {
return "", err
}
return path, nil
}
return OverrideContainersConfig, nil
}

func ifRootlessConfigPath() (string, error) {
if unshare.GetRootlessUID() > 0 {
path, err := rootlessConfigPath()
if err != nil {
return "", err
}
return path, nil
}
return "", nil
}

var defaultHelperBinariesDir = []string{
"/usr/local/libexec/podman",
"/usr/local/lib/podman",
Expand Down
48 changes: 4 additions & 44 deletions pkg/config/config_local_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,17 +365,17 @@ var _ = Describe("Config Local", func() {
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
}
// Given we do
oldContainersConf, envSet := os.LookupEnv("CONTAINERS_CONF")
os.Setenv("CONTAINERS_CONF", "/dev/null")
oldContainersConf, envSet := os.LookupEnv(containersConfEnv)
os.Setenv(containersConfEnv, "/dev/null")

// When
config, err := Default()

// Undo that
if envSet {
os.Setenv("CONTAINERS_CONF", oldContainersConf)
os.Setenv(containersConfEnv, oldContainersConf)
} else {
os.Unsetenv("CONTAINERS_CONF")
os.Unsetenv(containersConfEnv)
}
// Then
gomega.Expect(err).To(gomega.BeNil())
Expand All @@ -394,46 +394,6 @@ var _ = Describe("Config Local", func() {
gomega.Expect(envString).To(gomega.ContainSubstring("HTTP_PROXY=localhost"))
})

It("write", func() {
tmpfile := "containers.conf.test"
oldContainersConf, envSet := os.LookupEnv("CONTAINERS_CONF")
os.Setenv("CONTAINERS_CONF", tmpfile)
defer func() {
if envSet {
os.Setenv("CONTAINERS_CONF", oldContainersConf)
} else {
os.Unsetenv("CONTAINERS_CONF")
}
}()

config, err := ReadCustomConfig()
gomega.Expect(err).To(gomega.BeNil())
config.Containers.Devices.Set([]string{
"/dev/null:/dev/null:rw",
"/dev/sdc/",
"/dev/sdc:/dev/xvdc",
"/dev/sdc:rm",
})
boolTrue := true
config.Containers.Env.Set([]string{"A", "B", "C"})
config.Containers.Env.Attributes.Append = &boolTrue

err = config.Write()
gomega.Expect(err).To(gomega.BeNil())

fi, err := os.Stat(tmpfile)
gomega.Expect(err).To(gomega.BeNil())
perm := int(fi.Mode().Perm())
// 436 decimal = 644 octal
gomega.Expect(perm).To(gomega.Equal(420))
defer os.Remove(tmpfile)

writtenConfig, err := ReadCustomConfig()
gomega.Expect(err).To(gomega.BeNil())
gomega.Expect(writtenConfig.Containers.Devices).To(gomega.BeEquivalentTo(config.Containers.Devices))
gomega.Expect(writtenConfig.Containers.Env).To(gomega.BeEquivalentTo(config.Containers.Env))
gomega.Expect(writtenConfig.Containers.Env.Attributes.Append).To(gomega.BeEquivalentTo(&boolTrue))
})
It("Default Umask", func() {
// Given
// When
Expand Down
Loading

0 comments on commit 4729992

Please sign in to comment.