Add support to load runtime configuration from config file

Signed-off-by: Matthew Heon <matthew.heon@gmail.com>

Closes: #430
Approved by: rhatdan
This commit is contained in:
Matthew Heon
2018-03-01 11:56:22 -05:00
committed by Atomic Bot
parent 05c76f739c
commit d589c9fc38
2 changed files with 99 additions and 19 deletions

View File

@ -12,6 +12,7 @@ LIBEXECDIR ?= ${PREFIX}/libexec
MANDIR ?= ${PREFIX}/share/man
ETCDIR ?= ${DESTDIR}/etc
ETCDIR_LIBPOD ?= ${ETCDIR}/crio
ETCDIR_CONTAINERS ?= ${ETCDIR}/containers
BUILDTAGS ?= seccomp $(shell hack/btrfs_tag.sh) $(shell hack/libdm_tag.sh) $(shell hack/btrfs_installed_tag.sh) $(shell hack/ostree_tag.sh) $(shell hack/selinux_tag.sh)
BASHINSTALLDIR=${PREFIX}/share/bash-completion/completions
@ -151,6 +152,7 @@ install.man: docs
install ${SELINUXOPT} -m 644 $(filter %.1,$(MANPAGES)) -t $(MANDIR)/man1
install.config:
install ${SELINUXOPT} -D -m 644 libpod.conf ${ETCDIR_CONTAINERS}/libpod.conf
install ${SELINUXOPT} -D -m 644 seccomp.json $(ETCDIR_LIBPOD)/seccomp.json
install ${SELINUXOPT} -D -m 644 crio-umount.conf $(OCIUMOUNTINSTALLDIR)/crio-umount.conf

View File

@ -37,6 +37,14 @@ const (
SeccompDefaultPath = "/usr/share/containers/seccomp.json"
// SeccompOverridePath if this exists it overrides the default seccomp path
SeccompOverridePath = "/etc/crio/seccomp.json"
// ConfigPath is the path to the libpod configuration file
// This file is loaded to replace the builtin default config before
// runtime options (e.g. WithStorageConfig) are applied.
// If it is not present, the builtin default config is used instead
// This path can be overridden when the runtime is created by using
// NewRuntimeFromConfig() instead of NewRuntime()
ConfigPath = "/etc/containers/libpod.conf"
)
// A RuntimeOption is a functional option which alters the Runtime created by
@ -155,13 +163,83 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
// Copy the default configuration
deepcopier.Copy(defaultRuntimeConfig).To(runtime.config)
// Overwrite it with user-given configuration options
// Now overwrite it with the given configuration file, if it exists
// Do not fail on error, instead just use the builtin defaults
if _, err := os.Stat(ConfigPath); err == nil {
// Read the contents of the config file
contents, err := ioutil.ReadFile(ConfigPath)
if err == nil {
// Only proceed if we successfully read the file
_, err := toml.Decode(string(contents), runtime.config)
if err != nil {
// We may have just ruined our RuntimeConfig
// Make a new one to be safe
runtime.config = new(RuntimeConfig)
deepcopier.Copy(defaultRuntimeConfig).To(runtime.config)
}
}
}
// Overwrite config with user-given configuration options
for _, opt := range options {
if err := opt(runtime); err != nil {
return nil, errors.Wrapf(err, "error configuring runtime")
}
}
if err := makeRuntime(runtime); err != nil {
return nil, err
}
return runtime, nil
}
// NewRuntimeFromConfig creates a new container runtime using the given
// configuration file for its default configuration. Passed RuntimeOption
// functions can be used to mutate this configuration further.
// An error will be returned if the configuration file at the given path does
// not exist or cannot be loaded
func NewRuntimeFromConfig(configPath string, options ...RuntimeOption) (runtime *Runtime, err error) {
runtime = new(Runtime)
runtime.config = new(RuntimeConfig)
// Set two fields not in the TOML config
runtime.config.StateType = defaultRuntimeConfig.StateType
runtime.config.StorageConfig = storage.StoreOptions{}
// Check to see if the given configuration file exists
if _, err := os.Stat(configPath); err != nil {
return nil, errors.Wrapf(err, "error stating configuration file %s", configPath)
}
// Read contents of the config file
contents, err := ioutil.ReadFile(configPath)
if err != nil {
return nil, errors.Wrapf(err, "error reading configuration file %s", configPath)
}
// Decode configuration file
if _, err := toml.Decode(string(contents), runtime.config); err != nil {
return nil, errors.Wrapf(err, "error decoding configuration from file %s", configPath)
}
// Overwrite the config with user-given configuration options
for _, opt := range options {
if err := opt(runtime); err != nil {
return nil, errors.Wrapf(err, "error configuring runtime")
}
}
if err := makeRuntime(runtime); err != nil {
return nil, err
}
return runtime, nil
}
// Make a new runtime based on the given configuration
// Sets up containers/storage, state store, OCI runtime
func makeRuntime(runtime *Runtime) error {
// Find a working OCI runtime binary
foundRuntime := false
for _, path := range runtime.config.RuntimePath {
@ -177,7 +255,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
break
}
if !foundRuntime {
return nil, errors.Wrapf(ErrInvalidArg,
return errors.Wrapf(ErrInvalidArg,
"could not find a working runc binary (configured options: %v)",
runtime.config.RuntimePath)
}
@ -197,7 +275,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
break
}
if !foundConmon {
return nil, errors.Wrapf(ErrInvalidArg,
return errors.Wrapf(ErrInvalidArg,
"could not find a working conmon binary (configured options: %v)",
runtime.config.RuntimePath)
}
@ -205,7 +283,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
// Set up containers/storage
store, err := storage.GetStore(runtime.config.StorageConfig)
if err != nil {
return nil, err
return err
}
runtime.store = store
is.Transport.SetStore(store)
@ -224,7 +302,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
// images
storageService, err := getStorageService(runtime.store)
if err != nil {
return nil, err
return err
}
runtime.storageService = storageService
@ -239,7 +317,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
runtime.config.CgroupManager, runtime.config.TmpDir,
runtime.config.MaxLogSize, runtime.config.NoPivotRoot)
if err != nil {
return nil, err
return err
}
runtime.ociRuntime = ociRuntime
@ -247,7 +325,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
if err := os.MkdirAll(runtime.config.StaticDir, 0755); err != nil {
// The directory is allowed to exist
if !os.IsExist(err) {
return nil, errors.Wrapf(err, "error creating runtime static files directory %s",
return errors.Wrapf(err, "error creating runtime static files directory %s",
runtime.config.StaticDir)
}
}
@ -257,7 +335,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
if err := os.MkdirAll(lockDir, 0755); err != nil {
// The directory is allowed to exist
if !os.IsExist(err) {
return nil, errors.Wrapf(err, "error creating runtime lockfiles directory %s",
return errors.Wrapf(err, "error creating runtime lockfiles directory %s",
lockDir)
}
}
@ -267,7 +345,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
if err := os.MkdirAll(runtime.config.TmpDir, 0755); err != nil {
// The directory is allowed to exist
if !os.IsExist(err) {
return nil, errors.Wrapf(err, "error creating runtime temporary files directory %s",
return errors.Wrapf(err, "error creating runtime temporary files directory %s",
runtime.config.TmpDir)
}
}
@ -275,7 +353,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
// Set up the CNI net plugin
netPlugin, err := ocicni.InitCNI(runtime.config.CNIConfigDir, runtime.config.CNIPluginDir...)
if err != nil {
return nil, errors.Wrapf(err, "error configuring CNI network plugin")
return errors.Wrapf(err, "error configuring CNI network plugin")
}
runtime.netPlugin = netPlugin
@ -284,7 +362,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
case InMemoryStateStore:
state, err := NewInMemoryState()
if err != nil {
return nil, err
return err
}
runtime.state = state
case SQLiteStateStore:
@ -295,14 +373,14 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
if err := os.MkdirAll(specsDir, 0755); err != nil {
// The directory is allowed to exist
if !os.IsExist(err) {
return nil, errors.Wrapf(err, "error creating runtime OCI specs directory %s",
return errors.Wrapf(err, "error creating runtime OCI specs directory %s",
specsDir)
}
}
state, err := NewSQLState(dbPath, specsDir, runtime.lockDir, runtime)
if err != nil {
return nil, err
return err
}
runtime.state = state
case BoltDBStateStore:
@ -310,11 +388,11 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
state, err := NewBoltState(dbPath, runtime.lockDir, runtime)
if err != nil {
return nil, err
return err
}
runtime.state = state
default:
return nil, errors.Wrapf(ErrInvalidArg, "unrecognized state type passed")
return errors.Wrapf(ErrInvalidArg, "unrecognized state type passed")
}
// We now need to see if the system has restarted
@ -324,7 +402,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
runtimeAliveFile := filepath.Join(runtime.config.TmpDir, "alive")
aliveLock, err := storage.GetLockfile(runtimeAliveLock)
if err != nil {
return nil, errors.Wrapf(err, "error acquiring runtime init lock")
return errors.Wrapf(err, "error acquiring runtime init lock")
}
// Acquire the lock and hold it until we return
// This ensures that no two processes will be in runtime.refresh at once
@ -340,10 +418,10 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
// As such, it's not really a performance concern
if os.IsNotExist(err) {
if err2 := runtime.refresh(runtimeAliveFile); err2 != nil {
return nil, err2
return err2
}
} else {
return nil, errors.Wrapf(err, "error reading runtime status file %s", runtimeAliveFile)
return errors.Wrapf(err, "error reading runtime status file %s", runtimeAliveFile)
}
}
@ -351,7 +429,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
// further
runtime.valid = true
return runtime, nil
return nil
}
// GetConfig returns a copy of the configuration used by the runtime