From a6aca6d106192a577ea1f2b1c0d82ddb5c73c2bc Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 13 Nov 2018 09:49:22 +0100 Subject: rootless: create libpod.conf when it doesn't exist Signed-off-by: Giuseppe Scrivano --- libpod/runtime.go | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'libpod/runtime.go') diff --git a/libpod/runtime.go b/libpod/runtime.go index 318cd0369..9feae03fc 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -264,6 +264,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) { configPath := ConfigPath foundConfig := true + rootlessConfigPath := "" if rootless.IsRootless() { home := os.Getenv("HOME") if runtime.config.SignaturePolicyPath == "" { @@ -272,7 +273,10 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) { runtime.config.SignaturePolicyPath = newPath } } - configPath = filepath.Join(home, ".config/containers/libpod.conf") + + rootlessConfigPath = filepath.Join(home, ".config/containers/libpod.conf") + + configPath = rootlessConfigPath if _, err := os.Stat(configPath); err != nil { foundConfig = false } @@ -317,6 +321,22 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) { if err := makeRuntime(runtime); err != nil { return nil, err } + + if !foundConfig && rootlessConfigPath != "" { + os.MkdirAll(filepath.Dir(rootlessConfigPath), 0755) + file, err := os.OpenFile(rootlessConfigPath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) + if err != nil && !os.IsExist(err) { + return nil, errors.Wrapf(err, "cannot open file %s", rootlessConfigPath) + } + if err == nil { + defer file.Close() + enc := toml.NewEncoder(file) + if err := enc.Encode(runtime.config); err != nil { + os.Remove(rootlessConfigPath) + } + } + } + return runtime, nil } -- cgit v1.2.3-54-g00ecf From b0f79ff4df58c12fdfaff5c4a7c6e029cb566459 Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Thu, 29 Nov 2018 11:36:16 -0500 Subject: Move DB configuration up in runtime setup When we configure a runtime, we now will need to hit the DB early on, so we can verify the paths we're going to use for c/storage are correct. Signed-off-by: Matthew Heon --- libpod/runtime.go | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'libpod/runtime.go') diff --git a/libpod/runtime.go b/libpod/runtime.go index 9feae03fc..8615e5e12 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -426,6 +426,33 @@ func makeRuntime(runtime *Runtime) (err error) { runtime.config.ConmonPath) } + // Set up the state + switch runtime.config.StateType { + case InMemoryStateStore: + state, err := NewInMemoryState() + if err != nil { + return err + } + runtime.state = state + case SQLiteStateStore: + return errors.Wrapf(ErrInvalidArg, "SQLite state is currently disabled") + case BoltDBStateStore: + dbPath := filepath.Join(runtime.config.StaticDir, "bolt_state.db") + + state, err := NewBoltState(dbPath, runtime.lockDir, runtime) + if err != nil { + return err + } + runtime.state = state + default: + return errors.Wrapf(ErrInvalidArg, "unrecognized state type passed") + } + + if err := runtime.state.SetNamespace(runtime.config.Namespace); err != nil { + return errors.Wrapf(err, "error setting libpod namespace in state") + } + logrus.Debugf("Set libpod namespace to %q", runtime.config.Namespace) + // Set up containers/storage var store storage.Store if rootless.SkipStorageSetup() { @@ -540,33 +567,6 @@ func makeRuntime(runtime *Runtime) (err error) { } runtime.firewallBackend = fwBackend - // Set up the state - switch runtime.config.StateType { - case InMemoryStateStore: - state, err := NewInMemoryState() - if err != nil { - return err - } - runtime.state = state - case SQLiteStateStore: - return errors.Wrapf(ErrInvalidArg, "SQLite state is currently disabled") - case BoltDBStateStore: - dbPath := filepath.Join(runtime.config.StaticDir, "bolt_state.db") - - state, err := NewBoltState(dbPath, runtime.lockDir, runtime) - if err != nil { - return err - } - runtime.state = state - default: - return errors.Wrapf(ErrInvalidArg, "unrecognized state type passed") - } - - if err := runtime.state.SetNamespace(runtime.config.Namespace); err != nil { - return errors.Wrapf(err, "error setting libpod namespace in state") - } - logrus.Debugf("Set libpod namespace to %q", runtime.config.Namespace) - // We now need to see if the system has restarted // We check for the presence of a file in our tmp directory to verify this // This check must be locked to prevent races -- cgit v1.2.3-54-g00ecf From 137e0948aed96c3fe6412512e0d138eedf71d499 Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Sun, 2 Dec 2018 13:36:55 -0500 Subject: Make DB config validation an explicit step Previously, we implicitly validated runtime configuration against what was stored in the database as part of database init. Make this an explicit step, so we can call it after the database has been initialized. This will allow us to retrieve paths from the database and use them to overwrite our defaults if they differ. Signed-off-by: Matthew Heon --- libpod/boltdb_state.go | 29 ++++++++++++++++++++++++----- libpod/in_memory_state.go | 6 ++++++ libpod/runtime.go | 5 +++++ libpod/state.go | 9 +++++++++ 4 files changed, 44 insertions(+), 5 deletions(-) (limited to 'libpod/runtime.go') diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go index 7191b184a..37b309c0d 100644 --- a/libpod/boltdb_state.go +++ b/libpod/boltdb_state.go @@ -115,11 +115,6 @@ func NewBoltState(path, lockDir string, runtime *Runtime) (State, error) { return nil, errors.Wrapf(err, "error creating initial database layout") } - // Check runtime configuration - if err := checkRuntimeConfig(db, runtime); err != nil { - return nil, err - } - state.valid = true return state, nil @@ -243,6 +238,10 @@ func (s *BoltState) Refresh() error { // GetDBConfig retrieves runtime configuration fields that were created when // the database was first initialized func (s *BoltState) GetDBConfig() (*DBConfig, error) { + if !s.valid { + return nil, ErrDBClosed + } + cfg := new(DBConfig) db, err := s.getDBCon() @@ -282,6 +281,26 @@ func (s *BoltState) GetDBConfig() (*DBConfig, error) { return cfg, nil } +// ValidateDBConfig validates paths in the given runtime against the database +func (s *BoltState) ValidateDBConfig(runtime *Runtime) error { + if !s.valid { + return ErrDBClosed + } + + db, err := s.getDBCon() + if err != nil { + return err + } + defer s.closeDBCon(db) + + // Check runtime configuration + if err := checkRuntimeConfig(db, runtime); err != nil { + return err + } + + return nil +} + // SetNamespace sets the namespace that will be used for container and pod // retrieval func (s *BoltState) SetNamespace(ns string) error { diff --git a/libpod/in_memory_state.go b/libpod/in_memory_state.go index 3a775eb43..8cd2f47b9 100644 --- a/libpod/in_memory_state.go +++ b/libpod/in_memory_state.go @@ -78,6 +78,12 @@ func (s *InMemoryState) GetDBConfig() (*DBConfig, error) { return nil, ErrNotImplemented } +// ValidateDBConfig is not implemented for the in-memory state. +// Since we do nothing just return no error. +func (s *InMemoryState) ValidateDBConfig(runtime *Runtime) error { + return nil +} + // SetNamespace sets the namespace for container and pod retrieval. func (s *InMemoryState) SetNamespace(ns string) error { s.namespace = ns diff --git a/libpod/runtime.go b/libpod/runtime.go index 8615e5e12..2e76f159b 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -448,6 +448,11 @@ func makeRuntime(runtime *Runtime) (err error) { return errors.Wrapf(ErrInvalidArg, "unrecognized state type passed") } + // Validate our config against the database + if err := runtime.state.ValidateDBConfig(runtime); err != nil { + return err + } + if err := runtime.state.SetNamespace(runtime.config.Namespace); err != nil { return errors.Wrapf(err, "error setting libpod namespace in state") } diff --git a/libpod/state.go b/libpod/state.go index 7f4efa21b..99e2435a2 100644 --- a/libpod/state.go +++ b/libpod/state.go @@ -38,6 +38,15 @@ type State interface { // validate runtime configuration. GetDBConfig() (*DBConfig, error) + // ValidateDBConfig ralidates the config in the given Runtime struct + // against paths stored in the configured database. + // Libpod root and tmp dirs and c/storage root and tmp dirs and graph + // driver are validated. + // This is not implemented by the in-memory state, as it has no need to + // validate runtime configuration that may change over multiple runs of + // the program. + ValidateDBConfig(runtime *Runtime) error + // SetNamespace() sets the namespace for the store, and will determine // what containers are retrieved with container and pod retrieval calls. // A namespace of "", the empty string, acts as no namespace, and -- cgit v1.2.3-54-g00ecf From aa7ce33b7a7698d220f258bf9b29068be6fdb531 Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Sun, 2 Dec 2018 14:06:33 -0500 Subject: Add a struct indicating if some Runtime fields were set To configure runtime fields from the database, we need to know whether they were explicitly overwritten by the user (we don't want to overwrite anything that was explicitly set). Store a struct containing whether the variables we'll grab from the DB were explicitly set by the user so we know what we can and can't overwrite. This determines whether libpod runtime and static dirs were set via config file in a horribly hackish way (double TOML decode), but I can't think of a better way, and it shouldn't be that expensive as the libpod config is tiny. Signed-off-by: Matthew Heon --- libpod/options.go | 21 ++++++++++++++++++++- libpod/runtime.go | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) (limited to 'libpod/runtime.go') diff --git a/libpod/options.go b/libpod/options.go index 7f4e3ac6b..6783e2a39 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -30,9 +30,26 @@ func WithStorageConfig(config storage.StoreOptions) RuntimeOption { } rt.config.StorageConfig.RunRoot = config.RunRoot + if config.RunRoot != "" { + rt.configuredFrom.storageRunRootSet = true + } + rt.config.StorageConfig.GraphRoot = config.GraphRoot + if config.GraphRoot != "" { + rt.configuredFrom.storageGraphRootSet = true + } + rt.config.StorageConfig.GraphDriverName = config.GraphDriverName - rt.config.StaticDir = filepath.Join(config.GraphRoot, "libpod") + if config.GraphDriverName != "" { + rt.configuredFrom.storageGraphDriverSet = true + } + + // Only set our static dir if it was not already explicitly + // overridden + if config.GraphRoot != "" && !rt.configuredFrom.libpodStaticDirSet { + rt.config.StaticDir = filepath.Join(config.GraphRoot, "libpod") + rt.configuredFrom.libpodStaticDirSet = true + } rt.config.StorageConfig.GraphDriverOptions = make([]string, len(config.GraphDriverOptions)) copy(rt.config.StorageConfig.GraphDriverOptions, config.GraphDriverOptions) @@ -174,6 +191,7 @@ func WithStaticDir(dir string) RuntimeOption { } rt.config.StaticDir = dir + rt.configuredFrom.libpodStaticDirSet = true return nil } @@ -226,6 +244,7 @@ func WithTmpDir(dir string) RuntimeOption { } rt.config.TmpDir = dir + rt.configuredFrom.libpodTmpDirSet = true return nil } diff --git a/libpod/runtime.go b/libpod/runtime.go index 2e76f159b..1e05810fb 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -84,6 +84,7 @@ type Runtime struct { lock sync.RWMutex imageRuntime *image.Runtime firewallBackend firewall.FirewallBackend + configuredFrom *runtimeConfiguredFrom } // RuntimeConfig contains configuration options used to set up the runtime @@ -175,6 +176,20 @@ type RuntimeConfig struct { EnableLabeling bool `toml:"label"` } +// runtimeConfiguredFrom is a struct used during early runtime init to help +// assemble the full RuntimeConfig struct from defaults. +// It indicated whether several fields in the runtime configuration were set +// explicitly. +// If they were not, we may override them with information from the database, +// if it exists and differs from what is present in the system already. +type runtimeConfiguredFrom struct { + storageGraphDriverSet bool + storageGraphRootSet bool + storageRunRootSet bool + libpodStaticDirSet bool + libpodTmpDirSet bool +} + var ( defaultRuntimeConfig = RuntimeConfig{ // Leave this empty so containers/storage will use its defaults @@ -253,6 +268,7 @@ func SetXdgRuntimeDir(val string) error { func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) { runtime = new(Runtime) runtime.config = new(RuntimeConfig) + runtime.configuredFrom = new(runtimeConfiguredFrom) // Copy the default configuration tmpDir, err := getDefaultTmpDir() @@ -307,6 +323,25 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) { if err != nil { return nil, errors.Wrapf(err, "error reading configuration file %s", configPath) } + + // This is ugly, but we need to decode twice. + // Once to check if libpod static and tmp dirs were explicitly + // set (not enough to check if they're not the default value, + // might have been explicitly configured to the default). + // A second time to actually get a usable config. + tmpConfig := new(RuntimeConfig) + if _, err := toml.Decode(string(contents), tmpConfig); err != nil { + return nil, errors.Wrapf(err, "error decoding configuration file %s", + configPath) + } + + if tmpConfig.StaticDir != "" { + runtime.configuredFrom.libpodStaticDirSet = true + } + if tmpConfig.TmpDir != "" { + runtime.configuredFrom.libpodTmpDirSet = true + } + if _, err := toml.Decode(string(contents), runtime.config); err != nil { return nil, errors.Wrapf(err, "error decoding configuration file %s", configPath) } @@ -348,6 +383,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) { func NewRuntimeFromConfig(configPath string, options ...RuntimeOption) (runtime *Runtime, err error) { runtime = new(Runtime) runtime.config = new(RuntimeConfig) + runtime.configuredFrom = new(runtimeConfiguredFrom) // Set two fields not in the TOML config runtime.config.StateType = defaultRuntimeConfig.StateType -- cgit v1.2.3-54-g00ecf From 92ff83f5b9dd00ff91dc8c3d6b48f1e0b5c5f3e2 Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Sun, 2 Dec 2018 14:21:22 -0500 Subject: Set default paths from DB if not explicitly overridden If the DB contains default paths, and the user has not explicitly overridden them, use the paths in the DB over our own defaults. The DB validates these paths, so it would error and prevent operation if they did not match. As such, instead of erroring, we can use the DB's paths instead of our own. Signed-off-by: Matthew Heon --- libpod/in_memory_state.go | 5 +++-- libpod/runtime.go | 26 +++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) (limited to 'libpod/runtime.go') diff --git a/libpod/in_memory_state.go b/libpod/in_memory_state.go index 8cd2f47b9..77eba0cc6 100644 --- a/libpod/in_memory_state.go +++ b/libpod/in_memory_state.go @@ -73,9 +73,10 @@ func (s *InMemoryState) Refresh() error { return nil } -// GetDBConfig is not implemented for the in-memory state +// GetDBConfig is not implemented for in-memory state. +// As we do not store a config, return an empty one. func (s *InMemoryState) GetDBConfig() (*DBConfig, error) { - return nil, ErrNotImplemented + return &DBConfig{}, nil } // ValidateDBConfig is not implemented for the in-memory state. diff --git a/libpod/runtime.go b/libpod/runtime.go index 1e05810fb..e01fa781b 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -484,7 +484,31 @@ func makeRuntime(runtime *Runtime) (err error) { return errors.Wrapf(ErrInvalidArg, "unrecognized state type passed") } - // Validate our config against the database + // Grab config from the database so we can reset some defaults + dbConfig, err := runtime.state.GetDBConfig() + if err != nil { + return errors.Wrapf(err, "error retrieving runtime configuration from database") + } + + // Reset defaults if they were not explicitly set + if !runtime.configuredFrom.storageGraphDriverSet && dbConfig.GraphDriver != "" { + runtime.config.StorageConfig.GraphDriverName = dbConfig.GraphDriver + } + if !runtime.configuredFrom.storageGraphRootSet && dbConfig.StorageRoot != "" { + runtime.config.StorageConfig.GraphRoot = dbConfig.StorageRoot + } + if !runtime.configuredFrom.storageRunRootSet && dbConfig.StorageTmp != "" { + runtime.config.StorageConfig.RunRoot = dbConfig.StorageTmp + } + if !runtime.configuredFrom.libpodStaticDirSet && dbConfig.LibpodRoot != "" { + runtime.config.StaticDir = dbConfig.LibpodRoot + } + if !runtime.configuredFrom.libpodTmpDirSet && dbConfig.LibpodTmp != "" { + runtime.config.TmpDir = dbConfig.LibpodTmp + } + + // Validate our config against the database, now that we've set our + // final storage configuration if err := runtime.state.ValidateDBConfig(runtime); err != nil { return err } -- cgit v1.2.3-54-g00ecf From 562fa57dc9f497db772baa03bfa052082db68646 Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Sun, 2 Dec 2018 15:21:35 -0500 Subject: Move rootless storage config into libpod Previous commits ensured that we would use database-configured paths if not explicitly overridden. However, our runtime generation did unconditionally override storage config, which made this useless. Move rootless storage configuration setup to libpod, and change storage setup so we only override if a setting is explicitly set, so we can still override what we want. Signed-off-by: Matthew Heon --- cmd/podman/create.go | 2 +- cmd/podman/libpodruntime/runtime.go | 34 +++++++++------------------- cmd/podman/run.go | 2 +- libpod/options.go | 24 ++++++++++++-------- libpod/runtime.go | 9 ++++++++ pkg/util/utils.go | 44 ++++++++++++++++++------------------- 6 files changed, 57 insertions(+), 58 deletions(-) (limited to 'libpod/runtime.go') diff --git a/cmd/podman/create.go b/cmd/podman/create.go index bcf830c7c..1ef9fa47a 100644 --- a/cmd/podman/create.go +++ b/cmd/podman/create.go @@ -66,7 +66,7 @@ func createCmd(c *cli.Context) error { rootless.SetSkipStorageSetup(true) } - runtime, err := libpodruntime.GetContainerRuntime(c) + runtime, err := libpodruntime.GetRuntime(c) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/libpodruntime/runtime.go b/cmd/podman/libpodruntime/runtime.go index a4b3581be..13a821b9f 100644 --- a/cmd/podman/libpodruntime/runtime.go +++ b/cmd/podman/libpodruntime/runtime.go @@ -11,32 +11,18 @@ import ( // GetRuntime generates a new libpod runtime configured by command line options func GetRuntime(c *cli.Context) (*libpod.Runtime, error) { - storageOpts, err := util.GetDefaultStoreOptions() - if err != nil { - return nil, err - } - return GetRuntimeWithStorageOpts(c, &storageOpts) -} - -// GetContainerRuntime generates a new libpod runtime configured by command line options for containers -func GetContainerRuntime(c *cli.Context) (*libpod.Runtime, error) { - mappings, err := util.ParseIDMapping(c.StringSlice("uidmap"), c.StringSlice("gidmap"), c.String("subuidmap"), c.String("subgidmap")) - if err != nil { - return nil, err - } - storageOpts, err := util.GetDefaultStoreOptions() - if err != nil { - return nil, err - } - storageOpts.UIDMap = mappings.UIDMap - storageOpts.GIDMap = mappings.GIDMap - return GetRuntimeWithStorageOpts(c, &storageOpts) -} - -// GetRuntime generates a new libpod runtime configured by command line options -func GetRuntimeWithStorageOpts(c *cli.Context, storageOpts *storage.StoreOptions) (*libpod.Runtime, error) { + storageOpts := new(storage.StoreOptions) options := []libpod.RuntimeOption{} + if c.IsSet("uidmap") || c.IsSet("gidmap") || c.IsSet("subuidmap") || c.IsSet("subgidmap") { + mappings, err := util.ParseIDMapping(c.StringSlice("uidmap"), c.StringSlice("gidmap"), c.String("subuidmap"), c.String("subgidmap")) + if err != nil { + return nil, err + } + storageOpts.UIDMap = mappings.UIDMap + storageOpts.GIDMap = mappings.GIDMap + } + if c.GlobalIsSet("root") { storageOpts.GraphRoot = c.GlobalString("root") } diff --git a/cmd/podman/run.go b/cmd/podman/run.go index af6ced45d..a4b5c918e 100644 --- a/cmd/podman/run.go +++ b/cmd/podman/run.go @@ -44,7 +44,7 @@ func runCmd(c *cli.Context) error { rootless.SetSkipStorageSetup(true) } - runtime, err := libpodruntime.GetContainerRuntime(c) + runtime, err := libpodruntime.GetRuntime(c) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/libpod/options.go b/libpod/options.go index 6783e2a39..661bd8d91 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -29,18 +29,18 @@ func WithStorageConfig(config storage.StoreOptions) RuntimeOption { return ErrRuntimeFinalized } - rt.config.StorageConfig.RunRoot = config.RunRoot if config.RunRoot != "" { + rt.config.StorageConfig.RunRoot = config.RunRoot rt.configuredFrom.storageRunRootSet = true } - rt.config.StorageConfig.GraphRoot = config.GraphRoot if config.GraphRoot != "" { + rt.config.StorageConfig.GraphRoot = config.GraphRoot rt.configuredFrom.storageGraphRootSet = true } - rt.config.StorageConfig.GraphDriverName = config.GraphDriverName if config.GraphDriverName != "" { + rt.config.StorageConfig.GraphDriverName = config.GraphDriverName rt.configuredFrom.storageGraphDriverSet = true } @@ -51,14 +51,20 @@ func WithStorageConfig(config storage.StoreOptions) RuntimeOption { rt.configuredFrom.libpodStaticDirSet = true } - rt.config.StorageConfig.GraphDriverOptions = make([]string, len(config.GraphDriverOptions)) - copy(rt.config.StorageConfig.GraphDriverOptions, config.GraphDriverOptions) + if config.GraphDriverOptions != nil { + rt.config.StorageConfig.GraphDriverOptions = make([]string, len(config.GraphDriverOptions)) + copy(rt.config.StorageConfig.GraphDriverOptions, config.GraphDriverOptions) + } - rt.config.StorageConfig.UIDMap = make([]idtools.IDMap, len(config.UIDMap)) - copy(rt.config.StorageConfig.UIDMap, config.UIDMap) + if config.UIDMap != nil { + rt.config.StorageConfig.UIDMap = make([]idtools.IDMap, len(config.UIDMap)) + copy(rt.config.StorageConfig.UIDMap, config.UIDMap) + } - rt.config.StorageConfig.GIDMap = make([]idtools.IDMap, len(config.GIDMap)) - copy(rt.config.StorageConfig.GIDMap, config.GIDMap) + if config.GIDMap != nil { + rt.config.StorageConfig.GIDMap = make([]idtools.IDMap, len(config.GIDMap)) + copy(rt.config.StorageConfig.GIDMap, config.GIDMap) + } return nil } diff --git a/libpod/runtime.go b/libpod/runtime.go index e01fa781b..6a5d2ad39 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -278,6 +278,15 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) { deepcopier.Copy(defaultRuntimeConfig).To(runtime.config) runtime.config.TmpDir = tmpDir + if rootless.IsRootless() { + // If we're rootless, override the default storage config + storageConf, err := util.GetDefaultRootlessStoreOptions() + if err != nil { + return nil, errors.Wrapf(err, "error retrieving rootless storage config") + } + runtime.config.StorageConfig = storageConf + } + configPath := ConfigPath foundConfig := true rootlessConfigPath := "" diff --git a/pkg/util/utils.go b/pkg/util/utils.go index de29bc5d8..78484eb78 100644 --- a/pkg/util/utils.go +++ b/pkg/util/utils.go @@ -313,33 +313,31 @@ func getTomlStorage(storeOptions *storage.StoreOptions) *tomlConfig { return config } -// GetDefaultStoreOptions returns the storage ops for containers -func GetDefaultStoreOptions() (storage.StoreOptions, error) { - storageOpts := storage.DefaultStoreOptions - if rootless.IsRootless() { - var err error - storageOpts, err = GetRootlessStorageOpts() +// GetDefaultStoreOptions returns the storage ops for containers. +func GetDefaultRootlessStoreOptions() (storage.StoreOptions, error) { + var err error + storageOpts, err := GetRootlessStorageOpts() + if err != nil { + return storageOpts, err + } + + storageConf := filepath.Join(os.Getenv("HOME"), ".config/containers/storage.conf") + if _, err := os.Stat(storageConf); err == nil { + storage.ReloadConfigurationFile(storageConf, &storageOpts) + } else if os.IsNotExist(err) { + os.MkdirAll(filepath.Dir(storageConf), 0755) + file, err := os.OpenFile(storageConf, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) if err != nil { - return storageOpts, err + return storageOpts, errors.Wrapf(err, "cannot open %s", storageConf) } - storageConf := filepath.Join(os.Getenv("HOME"), ".config/containers/storage.conf") - if _, err := os.Stat(storageConf); err == nil { - storage.ReloadConfigurationFile(storageConf, &storageOpts) - } else if os.IsNotExist(err) { - os.MkdirAll(filepath.Dir(storageConf), 0755) - file, err := os.OpenFile(storageConf, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) - if err != nil { - return storageOpts, errors.Wrapf(err, "cannot open %s", storageConf) - } - - tomlConfiguration := getTomlStorage(&storageOpts) - defer file.Close() - enc := toml.NewEncoder(file) - if err := enc.Encode(tomlConfiguration); err != nil { - os.Remove(storageConf) - } + tomlConfiguration := getTomlStorage(&storageOpts) + defer file.Close() + enc := toml.NewEncoder(file) + if err := enc.Encode(tomlConfiguration); err != nil { + os.Remove(storageConf) } } + return storageOpts, nil } -- cgit v1.2.3-54-g00ecf From 03229239b018b611b5f0307dc0d11bb0fb15c1ae Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Sun, 2 Dec 2018 15:32:06 -0500 Subject: Do not initialize locks dir in BoltDB We already create the locks directory as part of the libpod runtime's init - no need to do it again as part of BoltDB's init. Signed-off-by: Matthew Heon --- libpod/boltdb_state.go | 10 ---------- libpod/runtime.go | 7 +++++++ 2 files changed, 7 insertions(+), 10 deletions(-) (limited to 'libpod/runtime.go') diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go index 37b309c0d..8b9b77a54 100644 --- a/libpod/boltdb_state.go +++ b/libpod/boltdb_state.go @@ -3,7 +3,6 @@ package libpod import ( "bytes" "encoding/json" - "os" "strings" "sync" @@ -62,15 +61,6 @@ func NewBoltState(path, lockDir string, runtime *Runtime) (State, error) { logrus.Debugf("Initializing boltdb state at %s", path) - // Make the directory that will hold container lockfiles - if err := os.MkdirAll(lockDir, 0750); err != nil { - // The directory is allowed to exist - if !os.IsExist(err) { - return nil, errors.Wrapf(err, "error creating lockfiles dir %s", lockDir) - } - } - state.lockDir = lockDir - db, err := bolt.Open(path, 0600, nil) if err != nil { return nil, errors.Wrapf(err, "error opening database %s", path) diff --git a/libpod/runtime.go b/libpod/runtime.go index 6a5d2ad39..9afa1bc10 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -285,6 +285,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) { return nil, errors.Wrapf(err, "error retrieving rootless storage config") } runtime.config.StorageConfig = storageConf + runtime.config.StaticDir = filepath.Join(storageConf.GraphRoot, "libpod") } configPath := ConfigPath @@ -516,6 +517,12 @@ func makeRuntime(runtime *Runtime) (err error) { runtime.config.TmpDir = dbConfig.LibpodTmp } + logrus.Debugf("Using graph driver %s", runtime.config.StorageConfig.GraphDriverName) + logrus.Debugf("Using graph root %s", runtime.config.StorageConfig.GraphRoot) + logrus.Debugf("Using run root %s", runtime.config.StorageConfig.RunRoot) + logrus.Debugf("Using static dir %s", runtime.config.StaticDir) + logrus.Debugf("Using tmp dir %s", runtime.config.TmpDir) + // Validate our config against the database, now that we've set our // final storage configuration if err := runtime.state.ValidateDBConfig(runtime); err != nil { -- cgit v1.2.3-54-g00ecf From 677c44446375680c5a69a9612f7df42b25de783f Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Mon, 3 Dec 2018 11:07:01 -0500 Subject: Ensure directory where we will make database exists Ensure that the directory where we will create the Podman db exists prior to creating the database - otherwise creating the DB will fail. Signed-off-by: Matthew Heon --- libpod/runtime.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'libpod/runtime.go') diff --git a/libpod/runtime.go b/libpod/runtime.go index 9afa1bc10..8b5bc32b4 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -472,6 +472,15 @@ func makeRuntime(runtime *Runtime) (err error) { runtime.config.ConmonPath) } + // Make the static files directory if it does not exist + if err := os.MkdirAll(runtime.config.StaticDir, 0700); err != nil { + // The directory is allowed to exist + if !os.IsExist(err) { + return errors.Wrapf(err, "error creating runtime static files directory %s", + runtime.config.StaticDir) + } + } + // Set up the state switch runtime.config.StateType { case InMemoryStateStore: @@ -601,15 +610,6 @@ func makeRuntime(runtime *Runtime) (err error) { } runtime.ociRuntime = ociRuntime - // Make the static files directory if it does not exist - if err := os.MkdirAll(runtime.config.StaticDir, 0755); err != nil { - // The directory is allowed to exist - if !os.IsExist(err) { - return errors.Wrapf(err, "error creating runtime static files directory %s", - runtime.config.StaticDir) - } - } - // Make a directory to hold container lockfiles lockDir := filepath.Join(runtime.config.TmpDir, "lock") if err := os.MkdirAll(lockDir, 0755); err != nil { -- cgit v1.2.3-54-g00ecf From 795fbba7695b03736acaf9abe75922404f5eea44 Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Mon, 3 Dec 2018 15:38:35 -0500 Subject: Revert changes to GetDefaultStoreOptions We don't need this for anything more than rootless work in Libpod now, but Buildah still uses it as it was originally written, so leave it intact as part of our API. Signed-off-by: Matthew Heon --- libpod/runtime.go | 2 +- pkg/util/utils.go | 45 +++++++++++++++++++++++---------------------- 2 files changed, 24 insertions(+), 23 deletions(-) (limited to 'libpod/runtime.go') diff --git a/libpod/runtime.go b/libpod/runtime.go index 8b5bc32b4..e69b63a24 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -280,7 +280,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) { if rootless.IsRootless() { // If we're rootless, override the default storage config - storageConf, err := util.GetDefaultRootlessStoreOptions() + storageConf, err := util.GetDefaultStoreOptions() if err != nil { return nil, errors.Wrapf(err, "error retrieving rootless storage config") } diff --git a/pkg/util/utils.go b/pkg/util/utils.go index ed79c4b46..e483253a4 100644 --- a/pkg/util/utils.go +++ b/pkg/util/utils.go @@ -313,32 +313,33 @@ func getTomlStorage(storeOptions *storage.StoreOptions) *tomlConfig { return config } -// GetDefaultRootlessStoreOptions returns the storage opts for rootless -// containers. -func GetDefaultRootlessStoreOptions() (storage.StoreOptions, error) { - var err error - storageOpts, err := GetRootlessStorageOpts() - if err != nil { - return storageOpts, err - } - - storageConf := filepath.Join(os.Getenv("HOME"), ".config/containers/storage.conf") - if _, err := os.Stat(storageConf); err == nil { - storage.ReloadConfigurationFile(storageConf, &storageOpts) - } else if os.IsNotExist(err) { - os.MkdirAll(filepath.Dir(storageConf), 0755) - file, err := os.OpenFile(storageConf, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) +// GetDefaultStoreOptions returns the default storage options for containers. +func GetDefaultStoreOptions() (storage.StoreOptions, error) { + storageOpts := storage.DefaultStoreOptions + if rootless.IsRootless() { + var err error + storageOpts, err = GetRootlessStorageOpts() if err != nil { - return storageOpts, errors.Wrapf(err, "cannot open %s", storageConf) + return storageOpts, err } - tomlConfiguration := getTomlStorage(&storageOpts) - defer file.Close() - enc := toml.NewEncoder(file) - if err := enc.Encode(tomlConfiguration); err != nil { - os.Remove(storageConf) + storageConf := filepath.Join(os.Getenv("HOME"), ".config/containers/storage.conf") + if _, err := os.Stat(storageConf); err == nil { + storage.ReloadConfigurationFile(storageConf, &storageOpts) + } else if os.IsNotExist(err) { + os.MkdirAll(filepath.Dir(storageConf), 0755) + file, err := os.OpenFile(storageConf, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) + if err != nil { + return storageOpts, errors.Wrapf(err, "cannot open %s", storageConf) + } + + tomlConfiguration := getTomlStorage(&storageOpts) + defer file.Close() + enc := toml.NewEncoder(file) + if err := enc.Encode(tomlConfiguration); err != nil { + os.Remove(storageConf) + } } } - return storageOpts, nil } -- cgit v1.2.3-54-g00ecf From a4b483c8484bb6fb9ae487264bccc663f007e711 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Sun, 2 Dec 2018 21:22:08 -0800 Subject: libpod/container_internal: Deprecate implicit hook directories Part of the motivation for 800eb863 (Hooks supports two directories, process default and override, 2018-09-17, #1487) was [1]: > We only use this for override. The reason this was caught is people > are trying to get hooks to work with CoreOS. You are not allowed to > write to /usr/share... on CoreOS, so they wanted podman to also look > at /etc, where users and third parties can write. But we'd also been disabling hooks completely for rootless users. And even for root users, the override logic was tricky when folks actually had content in both directories. For example, if you wanted to disable a hook from the default directory, you'd have to add a no-op hook to the override directory. Also, the previous implementation failed to handle the case where there hooks defined in the override directory but the default directory did not exist: $ podman version Version: 0.11.2-dev Go Version: go1.10.3 Git Commit: "6df7409cb5a41c710164c42ed35e33b28f3f7214" Built: Sun Dec 2 21:30:06 2018 OS/Arch: linux/amd64 $ ls -l /etc/containers/oci/hooks.d/test.json -rw-r--r--. 1 root root 184 Dec 2 16:27 /etc/containers/oci/hooks.d/test.json $ podman --log-level=debug run --rm docker.io/library/alpine echo 'successful container' 2>&1 | grep -i hook time="2018-12-02T21:31:19-08:00" level=debug msg="reading hooks from /usr/share/containers/oci/hooks.d" time="2018-12-02T21:31:19-08:00" level=warning msg="failed to load hooks: {}%!(EXTRA *os.PathError=open /usr/share/containers/oci/hooks.d: no such file or directory)" With this commit: $ podman --log-level=debug run --rm docker.io/library/alpine echo 'successful container' 2>&1 | grep -i hook time="2018-12-02T21:33:07-08:00" level=debug msg="reading hooks from /usr/share/containers/oci/hooks.d" time="2018-12-02T21:33:07-08:00" level=debug msg="reading hooks from /etc/containers/oci/hooks.d" time="2018-12-02T21:33:07-08:00" level=debug msg="added hook /etc/containers/oci/hooks.d/test.json" time="2018-12-02T21:33:07-08:00" level=debug msg="hook test.json matched; adding to stages [prestart]" time="2018-12-02T21:33:07-08:00" level=warning msg="implicit hook directories are deprecated; set --hooks-dir="/etc/containers/oci/hooks.d" explicitly to continue to load hooks from this directory" time="2018-12-02T21:33:07-08:00" level=error msg="container create failed: container_linux.go:336: starting container process caused "process_linux.go:399: container init caused \"process_linux.go:382: running prestart hook 0 caused \\\"error running hook: exit status 1, stdout: , stderr: oh, noes!\\\\n\\\"\"" (I'd setup the hook to error out). You can see that it's silenly ignoring the ENOENT for /usr/share/containers/oci/hooks.d and continuing on to load hooks from /etc/containers/oci/hooks.d. When it loads the hook, it also logs a warning-level message suggesting that callers explicitly configure their hook directories. That will help consumers migrate, so we can drop the implicit hook directories in some future release. When folks *do* explicitly configure hook directories (via the newly-public --hooks-dir and hooks_dir options), we error out if they're missing: $ podman --hooks-dir /does/not/exist run --rm docker.io/library/alpine echo 'successful container' error setting up OCI Hooks: open /does/not/exist: no such file or directory I've dropped the trailing "path" from the old, hidden --hooks-dir-path and hooks_dir_path because I think "dir(ectory)" is already enough context for "we expect a path argument". I consider this name change non-breaking because the old forms were undocumented. Coming back to rootless users, I've enabled hooks now. I expect they were previously disabled because users had no way to avoid /usr/share/containers/oci/hooks.d which might contain hooks that required root permissions. But now rootless users will have to explicitly configure hook directories, and since their default config is from ~/.config/containers/libpod.conf, it's a misconfiguration if it contains hooks_dir entries which point at directories with hooks that require root access. We error out so they can fix their libpod.conf. [1]: https://github.com/containers/libpod/pull/1487#discussion_r218149355 Signed-off-by: W. Trevor King --- cmd/podman/libpodruntime/runtime.go | 4 ++-- cmd/podman/main.go | 9 +++---- docs/libpod.conf.5.md | 12 ++++++++++ docs/podman.1.md | 24 +++++++++---------- libpod/container_internal.go | 48 ++++++++++++++++++++++--------------- libpod/container_internal_linux.go | 6 ++--- libpod/options.go | 15 ++++++------ libpod/runtime.go | 10 ++++---- libpod/testdata/config.toml | 2 +- test/e2e/run_test.go | 2 +- 10 files changed, 73 insertions(+), 59 deletions(-) (limited to 'libpod/runtime.go') diff --git a/cmd/podman/libpodruntime/runtime.go b/cmd/podman/libpodruntime/runtime.go index a4b3581be..f69eaf3a4 100644 --- a/cmd/podman/libpodruntime/runtime.go +++ b/cmd/podman/libpodruntime/runtime.go @@ -90,8 +90,8 @@ func GetRuntimeWithStorageOpts(c *cli.Context, storageOpts *storage.StoreOptions if c.GlobalIsSet("default-mounts-file") { options = append(options, libpod.WithDefaultMountsFile(c.GlobalString("default-mounts-file"))) } - if c.GlobalIsSet("hooks-dir-path") { - options = append(options, libpod.WithHooksDir(c.GlobalString("hooks-dir-path"))) + if c.GlobalIsSet("hooks-dir") { + options = append(options, libpod.WithHooksDir(c.GlobalStringSlice("hooks-dir")...)) } // TODO flag to set CNI plugins dir? diff --git a/cmd/podman/main.go b/cmd/podman/main.go index 6be192593..bcae04575 100644 --- a/cmd/podman/main.go +++ b/cmd/podman/main.go @@ -8,7 +8,6 @@ import ( "syscall" "github.com/containers/libpod/libpod" - "github.com/containers/libpod/pkg/hooks" _ "github.com/containers/libpod/pkg/hooks/0.1.0" "github.com/containers/libpod/pkg/rootless" "github.com/containers/libpod/version" @@ -206,11 +205,9 @@ func main() { Usage: "path to default mounts file", Hidden: true, }, - cli.StringFlag{ - Name: "hooks-dir-path", - Usage: "set the OCI hooks directory path", - Value: hooks.DefaultDir, - Hidden: true, + cli.StringSliceFlag{ + Name: "hooks-dir", + Usage: "set the OCI hooks directory path (may be set multiple times)", }, cli.IntFlag{ Name: "max-workers", diff --git a/docs/libpod.conf.5.md b/docs/libpod.conf.5.md index 198e927ee..d63baeb88 100644 --- a/docs/libpod.conf.5.md +++ b/docs/libpod.conf.5.md @@ -24,6 +24,18 @@ libpod to manage containers. **cgroup_manager**="" Specify the CGroup Manager to use; valid values are "systemd" and "cgroupfs" +**hooks_dir**=["*path*", ...] + + Each `*.json` file in the path configures a hook for Podman containers. For more details on the syntax of the JSON files and the semantics of hook injection, see `oci-hooks(5)`. Podman and libpod currently support both the 1.0.0 and 0.1.0 hook schemas, although the 0.1.0 schema is deprecated. + + Paths listed later in the array higher precedence (`oci-hooks(5)` discusses directory precedence). + + For the annotation conditions, libpod uses any annotations set in the generated OCI configuration. + + For the bind-mount conditions, only mounts explicitly requested by the caller via `--volume` are considered. Bind mounts that libpod inserts by default (e.g. `/dev/shm`) are not considered. + + If `hooks_dir` is unset for root callers, Podman and libpod will currently default to `/usr/share/containers/oci/hooks.d` and `/etc/containers/oci/hooks.d` in order of increasing precedence. Using these defaults is deprecated, and callers should migrate to explicitly setting `hooks_dir`. + **static_dir**="" Directory for persistent libpod files (database, etc) By default this will be configured relative to where containers/storage diff --git a/docs/podman.1.md b/docs/podman.1.md index b7433d850..bde349e6f 100644 --- a/docs/podman.1.md +++ b/docs/podman.1.md @@ -31,6 +31,18 @@ CGroup manager to use for container cgroups. Supported values are cgroupfs or sy Path to where the cpu performance results should be written +**--hooks-dir**=**path** + +Each `*.json` file in the path configures a hook for Podman containers. For more details on the syntax of the JSON files and the semantics of hook injection, see `oci-hooks(5)`. Podman and libpod currently support both the 1.0.0 and 0.1.0 hook schemas, although the 0.1.0 schema is deprecated. + +This option may be set multiple times; paths from later options have higher precedence (`oci-hooks(5)` discusses directory precedence). + +For the annotation conditions, libpod uses any annotations set in the generated OCI configuration. + +For the bind-mount conditions, only mounts explicitly requested by the caller via `--volume` are considered. Bind mounts that libpod inserts by default (e.g. `/dev/shm`) are not considered. + +If `--hooks-dir` is unset for root callers, Podman and libpod will currently default to `/usr/share/containers/oci/hooks.d` and `/etc/containers/oci/hooks.d` in order of increasing precedence. Using these defaults is deprecated, and callers should migrate to explicitly setting `--hooks-dir`. + **--log-level** Log messages above specified level: debug, info, warn, error (default), fatal or panic @@ -161,18 +173,6 @@ the exit codes follow the `chroot` standard, see below: The mounts.conf file specifies volume mount directories that are automatically mounted inside containers when executing the `podman run` or `podman start` commands. When Podman runs in rootless mode, the file `$HOME/.config/containers/mounts.conf` is also used. Please refer to containers-mounts.conf(5) for further details. -**OCI hooks JSON** (`/etc/containers/oci/hooks.d/*.json`, `/usr/share/containers/oci/hooks.d/*.json`) - - Each `*.json` file in `/etc/containers/oci/hooks.d` and `/usr/share/containers/oci/hooks.d` configures a hook for Podman containers, with `/etc/containers/oci/hooks.d` having higher precedence. For more details on the syntax of the JSON files and the semantics of hook injection, see `oci-hooks(5)`. - - Podman and libpod currently support both the 1.0.0 and 0.1.0 hook schemas, although the 0.1.0 schema is deprecated. - - For the annotation conditions, libpod uses any annotations set in the generated OCI configuration. - - For the bind-mount conditions, only mounts explicitly requested by the caller via `--volume` are considered. Bind mounts that libpod inserts by default (e.g. `/dev/shm`) are not considered. - - Hooks are not used when running in rootless mode. - **policy.json** (`/etc/containers/policy.json`) Signature verification policy files are used to specify policy, e.g. trusted keys, applicable when deciding whether to accept an image, or individual signatures of that image, as valid. diff --git a/libpod/container_internal.go b/libpod/container_internal.go index e31a8099c..934ad7a22 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -1168,10 +1168,6 @@ func (c *Container) saveSpec(spec *spec.Spec) error { } func (c *Container) setupOCIHooks(ctx context.Context, config *spec.Spec) (extensionStageHooks map[string][]spec.Hook, err error) { - if len(c.runtime.config.HooksDir) == 0 { - return nil, nil - } - var locale string var ok bool for _, envVar := range []string{ @@ -1199,25 +1195,39 @@ func (c *Container) setupOCIHooks(ctx context.Context, config *spec.Spec) (exten } } - allHooks := make(map[string][]spec.Hook) - for _, hDir := range c.runtime.config.HooksDir { - manager, err := hooks.New(ctx, []string{hDir}, []string{"poststop"}, lang) - if err != nil { - if c.runtime.config.HooksDirNotExistFatal || !os.IsNotExist(err) { - return nil, err - } - logrus.Warnf("failed to load hooks: %q", err) + if c.runtime.config.HooksDir == nil { + if rootless.IsRootless() { return nil, nil } - hooks, err := manager.Hooks(config, c.Spec().Annotations, len(c.config.UserVolumes) > 0) - if err != nil { - return nil, err - } - for i, hook := range hooks { - allHooks[i] = hook + allHooks := make(map[string][]spec.Hook) + for _, hDir := range []string{hooks.DefaultDir, hooks.OverrideDir} { + manager, err := hooks.New(ctx, []string{hDir}, []string{"poststop"}, lang) + if err != nil { + if os.IsNotExist(err) { + continue + } + return nil, err + } + hooks, err := manager.Hooks(config, c.Spec().Annotations, len(c.config.UserVolumes) > 0) + if err != nil { + return nil, err + } + if len(hooks) > 0 || config.Hooks != nil { + logrus.Warnf("implicit hook directories are deprecated; set --hooks-dir=%q explicitly to continue to load hooks from this directory", hDir) + } + for i, hook := range hooks { + allHooks[i] = hook + } } + return allHooks, nil } - return allHooks, nil + + manager, err := hooks.New(ctx, c.runtime.config.HooksDir, []string{"poststop"}, lang) + if err != nil { + return nil, err + } + + return manager.Hooks(config, c.Spec().Annotations, len(c.config.UserVolumes) > 0) } // mount mounts the container's root filesystem diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 8861d7728..780bf5279 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -224,10 +224,8 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { } } - if !rootless.IsRootless() { - if c.state.ExtensionStageHooks, err = c.setupOCIHooks(ctx, g.Config); err != nil { - return nil, errors.Wrapf(err, "error setting up OCI Hooks") - } + if c.state.ExtensionStageHooks, err = c.setupOCIHooks(ctx, g.Config); err != nil { + return nil, errors.Wrapf(err, "error setting up OCI Hooks") } // Bind builtin image volumes diff --git a/libpod/options.go b/libpod/options.go index 7f4e3ac6b..e1d0b5007 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -179,21 +179,20 @@ func WithStaticDir(dir string) RuntimeOption { } } -// WithHooksDir sets the directory to look for OCI runtime hooks config. -// Note we are not saving this in database, since this is really just for used -// for testing. -func WithHooksDir(hooksDir string) RuntimeOption { +// WithHooksDir sets the directories to look for OCI runtime hook configuration. +func WithHooksDir(hooksDirs ...string) RuntimeOption { return func(rt *Runtime) error { if rt.valid { return ErrRuntimeFinalized } - if hooksDir == "" { - return errors.Wrap(ErrInvalidArg, "empty-string hook directories are not supported") + for _, hooksDir := range hooksDirs { + if hooksDir == "" { + return errors.Wrap(ErrInvalidArg, "empty-string hook directories are not supported") + } } - rt.config.HooksDir = []string{hooksDir} - rt.config.HooksDirNotExistFatal = true + rt.config.HooksDir = hooksDirs return nil } } diff --git a/libpod/runtime.go b/libpod/runtime.go index 9feae03fc..e043715b1 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -12,7 +12,6 @@ import ( "github.com/containers/image/types" "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/firewall" - "github.com/containers/libpod/pkg/hooks" sysreg "github.com/containers/libpod/pkg/registries" "github.com/containers/libpod/pkg/rootless" "github.com/containers/libpod/pkg/util" @@ -141,11 +140,11 @@ type RuntimeConfig struct { // CNIDefaultNetwork is the network name of the default CNI network // to attach pods to CNIDefaultNetwork string `toml:"cni_default_network,omitempty"` - // HooksDir Path to the directory containing hooks configuration files + // HooksDir holds paths to the directories containing hooks + // configuration files. When the same filename is present in in + // multiple directories, the file in the directory listed last in + // this slice takes precedence. HooksDir []string `toml:"hooks_dir"` - // HooksDirNotExistFatal switches between fatal errors and non-fatal - // warnings if the configured HooksDir does not exist. - HooksDirNotExistFatal bool `toml:"hooks_dir_not_exist_fatal"` // DefaultMountsFile is the path to the default mounts file for testing // purposes only DefaultMountsFile string `toml:"-"` @@ -203,7 +202,6 @@ var ( "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", }, CgroupManager: SystemdCgroupsManager, - HooksDir: []string{hooks.DefaultDir, hooks.OverrideDir}, StaticDir: filepath.Join(storage.DefaultStoreOptions.GraphRoot, "libpod"), TmpDir: "", MaxLogSize: -1, diff --git a/libpod/testdata/config.toml b/libpod/testdata/config.toml index e19d36017..1d78f2083 100644 --- a/libpod/testdata/config.toml +++ b/libpod/testdata/config.toml @@ -14,7 +14,7 @@ seccomp_profile = "/etc/crio/seccomp.json" apparmor_profile = "crio-default" cgroup_manager = "cgroupfs" - hooks_dir_path = "/usr/share/containers/oci/hooks.d" + hooks_dir = ["/usr/share/containers/oci/hooks.d"] pids_limit = 2048 container_exits_dir = "/var/run/podman/exits" [crio.image] diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index 38504828b..b04116218 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -336,7 +336,7 @@ var _ = Describe("Podman run", func() { hooksDir := tempdir + "/hooks" os.Mkdir(hooksDir, 0755) fileutils.CopyFile("hooks/hooks.json", hooksDir) - os.Setenv("HOOK_OPTION", fmt.Sprintf("--hooks-dir-path=%s", hooksDir)) + os.Setenv("HOOK_OPTION", fmt.Sprintf("--hooks-dir=%s", hooksDir)) os.Remove(hcheck) session := podmanTest.Podman([]string{"run", ALPINE, "ls"}) session.Wait(10) -- cgit v1.2.3-54-g00ecf From e3882cfa2d1329d44c8a580418ea1d56804b331d Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Tue, 4 Dec 2018 13:50:38 -0500 Subject: Use runtime lockDir in BoltDB state Instead of storing the runtime's file lock dir in the BoltDB state, refer to the runtime inside the Bolt state instead, and use the path stored in the runtime. This is necessary since we moved DB initialization very far up in runtime init, before the locks dir is properly initialized (and it must happen before the locks dir can be created, as we use the DB to retrieve the proper path for the locks dir now). Signed-off-by: Matthew Heon --- libpod/boltdb_state.go | 4 +--- libpod/boltdb_state_internal.go | 4 ++-- libpod/runtime.go | 2 +- libpod/state_test.go | 3 ++- 4 files changed, 6 insertions(+), 7 deletions(-) (limited to 'libpod/runtime.go') diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go index 8b9b77a54..cb661d4e9 100644 --- a/libpod/boltdb_state.go +++ b/libpod/boltdb_state.go @@ -18,7 +18,6 @@ type BoltState struct { dbLock sync.Mutex namespace string namespaceBytes []byte - lockDir string runtime *Runtime } @@ -51,10 +50,9 @@ type BoltState struct { // containers/storage do not occur. // NewBoltState creates a new bolt-backed state database -func NewBoltState(path, lockDir string, runtime *Runtime) (State, error) { +func NewBoltState(path string, runtime *Runtime) (State, error) { state := new(BoltState) state.dbPath = path - state.lockDir = lockDir state.runtime = runtime state.namespace = "" state.namespaceBytes = nil diff --git a/libpod/boltdb_state_internal.go b/libpod/boltdb_state_internal.go index 05536e069..3f00657ea 100644 --- a/libpod/boltdb_state_internal.go +++ b/libpod/boltdb_state_internal.go @@ -266,7 +266,7 @@ func (s *BoltState) getContainerFromDB(id []byte, ctr *Container, ctrsBkt *bolt. } // Get the lock - lockPath := filepath.Join(s.lockDir, string(id)) + lockPath := filepath.Join(s.runtime.lockDir, string(id)) lock, err := storage.GetLockfile(lockPath) if err != nil { return errors.Wrapf(err, "error retrieving lockfile for container %s", string(id)) @@ -302,7 +302,7 @@ func (s *BoltState) getPodFromDB(id []byte, pod *Pod, podBkt *bolt.Bucket) error } // Get the lock - lockPath := filepath.Join(s.lockDir, string(id)) + lockPath := filepath.Join(s.runtime.lockDir, string(id)) lock, err := storage.GetLockfile(lockPath) if err != nil { return errors.Wrapf(err, "error retrieving lockfile for pod %s", string(id)) diff --git a/libpod/runtime.go b/libpod/runtime.go index e69b63a24..083ab1ec3 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -494,7 +494,7 @@ func makeRuntime(runtime *Runtime) (err error) { case BoltDBStateStore: dbPath := filepath.Join(runtime.config.StaticDir, "bolt_state.db") - state, err := NewBoltState(dbPath, runtime.lockDir, runtime) + state, err := NewBoltState(dbPath, runtime) if err != nil { return err } diff --git a/libpod/state_test.go b/libpod/state_test.go index 0f5da62e4..d93a371f3 100644 --- a/libpod/state_test.go +++ b/libpod/state_test.go @@ -52,8 +52,9 @@ func getEmptyBoltState() (s State, p string, p2 string, err error) { runtime := new(Runtime) runtime.config = new(RuntimeConfig) runtime.config.StorageConfig = storage.StoreOptions{} + runtime.lockDir = lockDir - state, err := NewBoltState(dbPath, lockDir, runtime) + state, err := NewBoltState(dbPath, runtime) if err != nil { return nil, "", "", err } -- cgit v1.2.3-54-g00ecf From 32aa45e344abc3e9501b0fddbac099285869e224 Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Tue, 4 Dec 2018 14:57:06 -0500 Subject: Don't initialize CNI when running as rootless We don't use CNI to configure networks for rootless containers, so no need to set it up. It may also cause issues with inotify, so disabling it resolves some potential problems. Signed-off-by: Matthew Heon --- libpod/runtime.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'libpod/runtime.go') diff --git a/libpod/runtime.go b/libpod/runtime.go index 9feae03fc..78092536d 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -523,11 +523,13 @@ func makeRuntime(runtime *Runtime) (err error) { } // Set up the CNI net plugin - netPlugin, err := ocicni.InitCNI(runtime.config.CNIDefaultNetwork, runtime.config.CNIConfigDir, runtime.config.CNIPluginDir...) - if err != nil { - return errors.Wrapf(err, "error configuring CNI network plugin") + if !rootless.IsRootless() { + netPlugin, err := ocicni.InitCNI(runtime.config.CNIDefaultNetwork, runtime.config.CNIConfigDir, runtime.config.CNIPluginDir...) + if err != nil { + return errors.Wrapf(err, "error configuring CNI network plugin") + } + runtime.netPlugin = netPlugin } - runtime.netPlugin = netPlugin // Set up a firewall backend backendType := "" -- cgit v1.2.3-54-g00ecf