registries.conf.d: add stances for the registries.conf

When loading the registries.conf, allow for loading additional files
from `/etc/containers/registries.conf.d`.  The files are loaded in
alpha-numerical order and specified fields will overwrite the previous
config.

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
Valentin Rothberg 2020-03-02 13:37:12 +01:00
parent 143904cdaa
commit eee0de5d00
8 changed files with 114 additions and 19 deletions

View File

@ -0,0 +1,33 @@
% CONTAINERS-REGISTRIES.CONF.D(5)
% Valentin Rothberg
% Mar 2020
# NAME
containers-registries.conf.d - directory for drop-in registries.conf files
# DESCRIPTION
CONTAINERS-REGISTRIES.CONF.D is a systemd-wide directory for drop-in
configuration files in the `containers-registries.conf(5)` format.
By default, the directory is located at `/etc/containers/registries.conf.d`.
# CONFIGURATION PRECEDENCE
Once the main configuration at `/etc/containers/registries.conf` is loaded, the
files in `/etc/containers/registries.conf.d` are loaded in alpha-numerical order.
Specified fields in a config will overwrite any previous setting.
For instance, setting the `unqualified-search-registries` in
`/etc/containers/registries.conf.d/myregistries.conf` will overwrite previous
settings in `/etc/containers/registries.conf`.
Note that all files must be specified in the same version of the
`containers-registries.conf(5)` format. The entire `[[registry]]` table will
always be overridden if set.
# SEE ALSO
`containers-registries.conf(5)`
# HISTORY
Mar 2020, Originally compiled by Valentin Rothberg <rothberg@redhat.com>

4
go.mod
View File

@ -39,10 +39,10 @@ require (
github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b // indirect
github.com/xeipuuv/gojsonschema v0.0.0-20190816131739-be0936907f66 github.com/xeipuuv/gojsonschema v0.0.0-20190816131739-be0936907f66
go.etcd.io/bbolt v1.3.3 // indirect go.etcd.io/bbolt v1.3.3 // indirect
golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708 golang.org/x/crypto v0.0.0-20200214034016-1d94cc7ab1c6
golang.org/x/net v0.0.0-20190628185345-da137c7871d7 golang.org/x/net v0.0.0-20190628185345-da137c7871d7
golang.org/x/sync v0.0.0-20190423024810-112230192c58 golang.org/x/sync v0.0.0-20190423024810-112230192c58
golang.org/x/sys v0.0.0-20191127021746-63cb32ae39b2 golang.org/x/sys v0.0.0-20200217220822-9197077df867
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
k8s.io/client-go v0.0.0-20170217214107-bcde30fb7eae k8s.io/client-go v0.0.0-20170217214107-bcde30fb7eae
) )

View File

@ -2,7 +2,6 @@ package sysregistriesv2
import ( import (
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
@ -26,6 +25,16 @@ var systemRegistriesConfPath = builtinRegistriesConfPath
// DO NOT change this, instead see systemRegistriesConfPath above. // DO NOT change this, instead see systemRegistriesConfPath above.
const builtinRegistriesConfPath = "/etc/containers/registries.conf" const builtinRegistriesConfPath = "/etc/containers/registries.conf"
// systemRegistriesConfDirPath is the path to the system-wide registry
// configuration directory and is used to add/subtract potential registries for
// obtaining images. You can override this at build time with
// -ldflags '-X github.com/containers/image/sysregistries.systemRegistriesConfDirecotyPath=$your_path'
var systemRegistriesConfDirPath = builtinRegistriesConfDirPath
// builtinRegistriesConfDirPath is the path to the registry configuration directory.
// DO NOT change this, instead see systemRegistriesConfDirectoryPath above.
const builtinRegistriesConfDirPath = "/etc/containers/registries.conf.d"
// Endpoint describes a remote location of a registry. // Endpoint describes a remote location of a registry.
type Endpoint struct { type Endpoint struct {
// The endpoint's remote location. // The endpoint's remote location.
@ -360,16 +369,45 @@ func TryUpdatingCache(ctx *types.SystemContext) (*V2RegistriesConf, error) {
defer configMutex.Unlock() defer configMutex.Unlock()
// load the config // load the config
config, err := loadRegistryConf(configPath) config := &tomlConfig{}
if err != nil { if err := config.loadConfig(configPath); err != nil {
// Return an empty []Registry if we use the default config, // Return an empty []Registry if we use the default config,
// which implies that the config path of the SystemContext // which implies that the config path of the SystemContext
// isn't set. Note: if ctx.SystemRegistriesConfPath points to // isn't set. Note: if ctx.SystemRegistriesConfPath points to
// the default config, we will still return an error. // the default config, we will still return an error.
if os.IsNotExist(err) && (ctx == nil || ctx.SystemRegistriesConfPath == "") { if os.IsNotExist(err) && (ctx == nil || ctx.SystemRegistriesConfPath == "") {
return &V2RegistriesConf{Registries: []Registry{}}, nil config = &tomlConfig{}
config.V2RegistriesConf = V2RegistriesConf{Registries: []Registry{}}
} else {
return nil, err
} }
return nil, err }
// Load the configs from the conf directory path.
confDir := systemRegistriesConfDirPath
if ctx != nil && ctx.SystemRegistriesConfDirPath != "" {
confDir = ctx.SystemRegistriesConfDirPath
}
err := filepath.Walk(confDir,
// WalkFunc to read additional
func(path string, info os.FileInfo, err error) error {
switch {
case info == nil:
// registries.conf.d doesn't exist
return nil
case info.IsDir():
// ignore directories
return nil
default:
// expect all files to be a config
return config.loadConfig(path)
}
},
)
if err != nil && !os.IsNotExist(err) {
// Ignore IsNotExist errors: most systems won't have a
// registries.conf.d directory.
return nil, errors.Wrapf(err, "error reading registries.conf.d")
} }
v2Config := &config.V2RegistriesConf v2Config := &config.V2RegistriesConf
@ -470,16 +508,12 @@ func FindRegistry(ctx *types.SystemContext, ref string) (*Registry, error) {
return nil, nil return nil, nil
} }
// Loads the registry configuration file from the filesystem and then unmarshals // tomlConfig loads the unmarshals the configuration at the specified path.
// it. Returns the unmarshalled object. // Note that the tomlConfig's fields will be overridden if they are set in
func loadRegistryConf(configPath string) (*tomlConfig, error) { // specified path. This behavior is necessary for registries.conf.d stances
config := &tomlConfig{} // behavior.
func (t *tomlConfig) loadConfig(path string) error {
configBytes, err := ioutil.ReadFile(configPath) logrus.Debugf("Loading registries.conf %q", path)
if err != nil { _, err := toml.DecodeFile(path, t)
return nil, err return err
}
err = toml.Unmarshal(configBytes, &config)
return config, err
} }

View File

@ -463,3 +463,18 @@ func TestTryUpdatingCache(t *testing.T) {
assert.Nil(t, registries) assert.Nil(t, registries)
assert.Equal(t, 1, len(configCache)) assert.Equal(t, 1, len(configCache))
} }
func TestRegistriesConfDirectory(t *testing.T) {
ctx := &types.SystemContext{
SystemRegistriesConfPath: "testdata/base-for-registries.d.conf",
SystemRegistriesConfDirPath: "testdata/registries.conf.d",
}
configCache = make(map[string]*V2RegistriesConf)
registries, err := TryUpdatingCache(ctx)
assert.Nil(t, err)
assert.NotNil(t, registries)
assert.Equal(t, registries.UnqualifiedSearchRegistries, []string{"example-overwrite.com"})
assert.Equal(t, len(registries.Registries), 1)
assert.Equal(t, registries.Registries[0].Location, "2.com")
}

View File

@ -0,0 +1,5 @@
unqualified-search-registries = ["example.com"]
[[registry]]
location = "base.com"
insecure = true

View File

@ -0,0 +1,4 @@
unqualified-search-registries = ["example-overwrite.com"]
[[registry]]
location = "1.com"

View File

@ -0,0 +1,2 @@
[[registry]]
location = "2.com"

View File

@ -497,6 +497,8 @@ type SystemContext struct {
RegistriesDirPath string RegistriesDirPath string
// Path to the system-wide registries configuration file // Path to the system-wide registries configuration file
SystemRegistriesConfPath string SystemRegistriesConfPath string
// Path to the system-wide registries configuration directory
SystemRegistriesConfDirPath string
// If not "", overrides the default path for the authentication file, but only new format files // If not "", overrides the default path for the authentication file, but only new format files
AuthFilePath string AuthFilePath string
// if not "", overrides the default path for the authentication file, but with the legacy format; // if not "", overrides the default path for the authentication file, but with the legacy format;