From d589c9fc3874def8ec2ed09d66ca33180f053c39 Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Thu, 1 Mar 2018 11:56:22 -0500 Subject: Add support to load runtime configuration from config file Signed-off-by: Matthew Heon Closes: #430 Approved by: rhatdan --- Makefile | 2 + libpod/runtime.go | 116 +++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 99 insertions(+), 19 deletions(-) diff --git a/Makefile b/Makefile index 3fa9fa2ef..50766900a 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/libpod/runtime.go b/libpod/runtime.go index 2876d8798..4e1a60ea6 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -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 -- cgit v1.2.3-54-g00ecf