-
Notifications
You must be signed in to change notification settings - Fork 267
Add support for drop-in config #1885
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -49,6 +49,12 @@ var ( | |
| defaultConfigFile = SystemConfigFile | ||
| // DefaultStoreOptions is a reasonable default set of options. | ||
| defaultStoreOptions StoreOptions | ||
|
|
||
| // defaultOverrideConfigFile path to override the default system wide storage.conf file | ||
| defaultOverrideConfigFile = "/etc/containers/storage.conf" | ||
|
|
||
| // defaultDropInConfigDir path to the folder containing drop in config files | ||
| defaultDropInConfigDir = defaultOverrideConfigFile + ".d" | ||
| ) | ||
|
|
||
| func loadDefaultStoreOptions() { | ||
|
|
@@ -114,11 +120,53 @@ func loadDefaultStoreOptions() { | |
|
|
||
| // loadStoreOptions returns the default storage ops for containers | ||
| func loadStoreOptions() (StoreOptions, error) { | ||
| storageConf, err := DefaultConfigFile() | ||
| baseConf, err := DefaultConfigFile() | ||
| if err != nil { | ||
| return defaultStoreOptions, err | ||
| } | ||
|
|
||
| // Load the base config file | ||
| baseOptions, err := loadStoreOptionsFromConfFile(baseConf) | ||
| if err != nil { | ||
| return defaultStoreOptions, err | ||
| } | ||
| return loadStoreOptionsFromConfFile(storageConf) | ||
|
|
||
| if _, err := os.Stat(defaultDropInConfigDir); err == nil { | ||
| // The directory exists, so merge the configuration from this directory | ||
| err = mergeConfigFromDirectory(&baseOptions, defaultDropInConfigDir) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure we should hardcode a specific directory, but instead try to load each file from the
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks @giuseppe, that's a good idea. I modified the code to set the drop-in config dir to |
||
| if err != nil { | ||
| return defaultStoreOptions, err | ||
| } | ||
| } else if !os.IsNotExist(err) { | ||
| // There was an error other than the directory not existing | ||
| return defaultStoreOptions, err | ||
| } | ||
|
|
||
| return baseOptions, nil | ||
| } | ||
|
|
||
| func mergeConfigFromDirectory(baseOptions *StoreOptions, configDir string) error { | ||
| return filepath.Walk(configDir, func(path string, info os.FileInfo, err error) error { | ||
| if err != nil { | ||
| return err | ||
| } | ||
| if info.IsDir() { | ||
| return nil | ||
| } | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice update. Should check for file extension here.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But a text file without a
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm. We support a file without an extension?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as long as the content of the file is valid, it shouldn't matter, right? crio doesn't enforce the extension either - https://github.com/cri-o/cri-o/blob/256fda5ac98de1d67e26133d0b25df2a74e2ebd2/pkg/config/config.go#L776
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Usually there is a filter, but this is fine.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. one risk is temporary files written by editor and the like. It mostly only is an issue if we're reloading automatically. If it's manually triggered (like here) then the user usually has written and edited the editor before the reload happens...
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think requiring a .conf or .toml extension could be a nice change both here and cri-o. @sohankunkerkar added a filter for the kubelet's drop-in work
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes require a .conf extension, that follows what we have done with other dropin files.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks @rphillips @haircommander @rhatdan for this feedback. I have updated the code to select files with |
||
| // Only consider files with .conf extension | ||
| if filepath.Ext(path) != ".conf" { | ||
| return nil | ||
| } | ||
|
|
||
| // Load drop-in options from the current file | ||
| err = ReloadConfigurationFile(path, baseOptions, false) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| return nil | ||
| }) | ||
| } | ||
|
|
||
| // usePerUserStorage returns whether the user private storage must be used. | ||
|
|
@@ -399,7 +447,7 @@ func ReloadConfigurationFileIfNeeded(configFile string, storeOptions *StoreOptio | |
| return nil | ||
| } | ||
|
|
||
| if err := ReloadConfigurationFile(configFile, storeOptions); err != nil { | ||
| if err := ReloadConfigurationFile(configFile, storeOptions, true); err != nil { | ||
| return err | ||
| } | ||
|
|
||
|
|
@@ -412,7 +460,7 @@ func ReloadConfigurationFileIfNeeded(configFile string, storeOptions *StoreOptio | |
|
|
||
| // ReloadConfigurationFile parses the specified configuration file and overrides | ||
| // the configuration in storeOptions. | ||
| func ReloadConfigurationFile(configFile string, storeOptions *StoreOptions) error { | ||
| func ReloadConfigurationFile(configFile string, storeOptions *StoreOptions, initializeOptions bool) error { | ||
| config := new(TomlConfig) | ||
|
|
||
| meta, err := toml.DecodeFile(configFile, &config) | ||
|
|
@@ -428,8 +476,11 @@ func ReloadConfigurationFile(configFile string, storeOptions *StoreOptions) erro | |
| } | ||
| } | ||
|
|
||
| // Clear storeOptions of previous settings | ||
| *storeOptions = StoreOptions{} | ||
| if initializeOptions { | ||
| // Clear storeOptions of previous settings | ||
| *storeOptions = StoreOptions{} | ||
| } | ||
|
|
||
| if config.Storage.Driver != "" { | ||
| storeOptions.GraphDriverName = config.Storage.Driver | ||
| } | ||
|
|
@@ -519,8 +570,13 @@ func ReloadConfigurationFile(configFile string, storeOptions *StoreOptions) erro | |
| storeOptions.PullOptions = config.Storage.Options.PullOptions | ||
| } | ||
|
|
||
| storeOptions.DisableVolatile = config.Storage.Options.DisableVolatile | ||
| storeOptions.TransientStore = config.Storage.TransientStore | ||
| if config.Storage.Options.DisableVolatile { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How do I set It seems to me that all of this is going to require some other approach, and probably very detailed testing.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or, alternatively, be very strict and very restrictive about which options are supported in drop-ins, support/test only those, and hard-fail if any others are present. Then we can add support for more options over time … assuming it’s sufficiently certain adding the others will actually be possible in the future.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed, we need to call
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks @rphillips. If I get the keySet := make(map[string]bool)
for _, key := range meta.Keys() {
keySet[key.String()] = true
}
if _, ok := keySet["storage.transient_store"]; ok {
storeOptions.TransientStore = config.Storage.TransientStore
}
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The updated snippet of the included test looks like this, contents := []string{
`[storage]
runroot = 'temp/run1'
graphroot = 'temp/graph1'
transient_store = false`,
`[storage]
runroot = 'temp/run2'
graphroot = 'temp/graph2'`,
`[storage]
runroot = 'should/ignore'
graphroot = 'should/ignore'`,
`[storage]
runroot = 'temp/run3'`,
`[storage]
runroot = 'temp/run4'
graphroot = 'temp/graph4'`,
}
for i, fileName := range fileNames {
filePath := filepath.Join(tempDir, fileName)
if err := os.WriteFile(filePath, []byte(contents[i]), 0o666); err != nil {
t.Fatalf("Failed to write to temp file: %v", err)
}
}
// Set base options
baseOptions := StoreOptions{
RunRoot: "initial/run",
GraphRoot: "initial/graph",
TransientStore: true,
}
// Expected results after merging configurations from only .conf files
expectedOptions := StoreOptions{
RunRoot: "temp/run3", // Last .conf file (config3.conf) read overrides earlier values
GraphRoot: "temp/graph2",
TransientStore: false,
}
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I sorta worry about mergo setting options to false. Did we get past this issue in MCO where values being set to false wouldn’t get set?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah the mergo option didn't work. It does set the option to false as you predicated. code is at, harche@f0b92df#diff-5c0b7c9ae084e6c4613c438d00cede106862b604f184a331df1c3806cfbd11d2R164 So it seems like our only option is to use BTW, which MCO issue are you talking about?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. https://issues.redhat.com/browse/OCPBUGS-14399 I remember we had to hack around it.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. systemd has definitely benefited from a single consistent config file format with consistent semantics and merge support.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Explicitly iterating over the keys seems like it'd work, but another thing to do is to use nullable values for all entries. This is much more elegant in Rust of course...here's how I recently did a basic "mergeable toml" in bootc: https://github.com/containers/bootc/blob/f152bfe8da47c3bfbafca33c2142d10611375fa3/lib/src/install/config.rs#L47 (Note each entry is |
||
| storeOptions.DisableVolatile = config.Storage.Options.DisableVolatile | ||
| } | ||
|
|
||
| if config.Storage.TransientStore { | ||
| storeOptions.TransientStore = config.Storage.TransientStore | ||
| } | ||
|
|
||
| storeOptions.GraphDriverOptions = append(storeOptions.GraphDriverOptions, cfg.GetGraphDriverOptions(storeOptions.GraphDriverName, config.Storage.Options)...) | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.