diff --git a/pkg/config/config.go b/pkg/config/config.go index 4ad791f3dcb..8c7ef2a8e6b 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -519,6 +519,10 @@ func (c *Config) UpdateFromFile(path string) error { // Returns errors encountered when reading or parsing the files, or nil // otherwise. func (c *Config) UpdateFromDropInFile(path string) error { + // keeps the storage options from storage.conf and merge it to crio config + var storageOpts []string + storageOpts = append(storageOpts, c.StorageOptions...) + data, err := ioutil.ReadFile(path) if err != nil { return err @@ -538,6 +542,10 @@ func (c *Config) UpdateFromDropInFile(path string) error { delete(c.Runtimes, defaultRuntime) } + storageOpts = append(storageOpts, t.Crio.RootConfig.StorageOptions...) + storageOpts = removeDupStorageOpts(storageOpts) + t.Crio.RootConfig.StorageOptions = storageOpts + // Registries are deprecated in cri-o.conf and turned into a NOP. // Users should use registries.conf instead, so let's log it. if len(t.Crio.Image.Registries) > 0 { @@ -549,6 +557,24 @@ func (c *Config) UpdateFromDropInFile(path string) error { return nil } +// removeDupStorageOpts removes duplicated storage option from the list +// keeps the last appearance +func removeDupStorageOpts(storageOpts []string) []string { + var resOpts []string + opts := make(map[string]bool) + for i := len(storageOpts) - 1; i >= 0; i-- { + if ok := opts[storageOpts[i]]; ok { + continue + } + opts[storageOpts[i]] = true + resOpts = append(resOpts, storageOpts[i]) + } + for i, j := 0, len(resOpts)-1; i < j; i, j = i+1, j-1 { + resOpts[i], resOpts[j] = resOpts[j], resOpts[i] + } + return resOpts +} + // UpdateFromPath recursively iterates the provided path and updates the // configuration for it func (c *Config) UpdateFromPath(path string) error { diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 93aed25528c..3b533851cda 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -835,6 +835,37 @@ var _ = t.Describe("Config", func() { Expect(sut.PidsLimit).To(BeEquivalentTo(2048)) }) + It("should inherit storage_options from storage.conf and remove duplicates", func() { + f := t.MustTempFile("config") + // Given + Expect(ioutil.WriteFile(f, + []byte(` + [crio] + storage_option = [ + "foo=bar", + ]`, + ), 0), + ).To(BeNil()) + for _, tc := range []struct { + opts []string + expect []string + }{ + {[]string{"option1=v1", "option2=v2", "option3=v3"}, []string{"option1=v1", "option2=v2", "option3=v3", "foo=bar"}}, + {[]string{"option1=v1", "option3=v3", "option2=v2", "option3=v3"}, []string{"option1=v1", "option2=v2", "option3=v3", "foo=bar"}}, + {[]string{"option1=v1", "option2=v2", "option3=v3", "option1=v1"}, []string{"option2=v2", "option3=v3", "option1=v1", "foo=bar"}}, + {[]string{"option1=v1", "option2=v2", "option3=v3", "option4=v4", "option3=v3", "option1=v1"}, []string{"option2=v2", "option4=v4", "option3=v3", "option1=v1", "foo=bar"}}, + } { + // When + defaultcfg := defaultConfig() + defaultcfg.StorageOptions = tc.opts + err := defaultcfg.UpdateFromFile(f) + + // Then + Expect(err).To(BeNil()) + Expect(defaultcfg.RootConfig.StorageOptions).To(Equal(tc.expect)) + } + }) + It("should succeed with custom runtime", func() { // Given f := t.MustTempFile("config")