Skip to content

Commit 3663c3d

Browse files
authored
Use /var/lib/cni/ovs-cni/cache dir to store config cache (#304)
Old path ("/tmp/ovscache") is cleaned up after reboot on some operating systems. Lack of the cache entries may prevent ovs-cni to do a proper cleanup on CmdDel. Use /var/lib/cni/ovs-cni/cache as a persistent cache dir. Signed-off-by: Yury Kulazhenkov <[email protected]>
1 parent fb9f655 commit 3663c3d

File tree

3 files changed

+165
-14
lines changed

3 files changed

+165
-14
lines changed

pkg/utils/cache.go

+51-14
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,17 @@ package utils
1919
import (
2020
"encoding/json"
2121
"fmt"
22-
"io/ioutil"
2322
"os"
2423
"path/filepath"
2524
)
2625

2726
var (
2827
// DefaultCacheDir used for caching
29-
DefaultCacheDir = "/tmp/ovscache"
28+
DefaultCacheDir = "/var/lib/cni/ovs-cni/cache"
29+
// OldDefaultCacheDir path to the old caching dir
30+
OldDefaultCacheDir = "/tmp/ovscache"
31+
// used for tests
32+
rootDir = ""
3033
)
3134

3235
// SaveCache takes in key as string and a json encoded struct Conf and save this Conf in cache dir
@@ -35,13 +38,13 @@ func SaveCache(key string, conf interface{}) error {
3538
if err != nil {
3639
return fmt.Errorf("error serializing delegate conf: %v", err)
3740
}
38-
41+
path := getKeyPath(key)
42+
cacheDir := filepath.Dir(path)
3943
// save the rendered conf for cmdDel
40-
if err = os.MkdirAll(DefaultCacheDir, 0700); err != nil {
41-
return fmt.Errorf("failed to create the sriov data directory(%q): %v", DefaultCacheDir, err)
44+
if err = os.MkdirAll(cacheDir, 0700); err != nil {
45+
return fmt.Errorf("failed to create the sriov data directory(%q): %v", cacheDir, err)
4246
}
43-
path := getKeyPath(key)
44-
err = ioutil.WriteFile(path, confBytes, 0600)
47+
err = os.WriteFile(path, confBytes, 0600)
4548
if err != nil {
4649
return fmt.Errorf("failed to write container data in the path(%q): %v", path, err)
4750
}
@@ -51,22 +54,56 @@ func SaveCache(key string, conf interface{}) error {
5154
// ReadCache read cached conf from disk for the given key and returns data in byte array
5255
func ReadCache(key string) ([]byte, error) {
5356
path := getKeyPath(key)
54-
data, err := ioutil.ReadFile(path)
57+
oldPath := getOldKeyPath(key)
58+
data, err := readCacheFile(path)
5559
if err != nil {
56-
return nil, fmt.Errorf("failed to read container data in the path(%q): %v", path, err)
60+
return nil, err
61+
}
62+
if data == nil {
63+
data, err = readCacheFile(oldPath)
64+
if err != nil {
65+
return nil, err
66+
}
5767
}
58-
return data, err
68+
if data == nil {
69+
return nil, fmt.Errorf("failed to read container data from old(%q) and current(%q) path: not found", oldPath, path)
70+
}
71+
return data, nil
5972
}
6073

6174
// CleanCache removes cached conf from disk for the given key
6275
func CleanCache(key string) error {
63-
path := getKeyPath(key)
64-
if err := os.Remove(path); err != nil {
65-
return fmt.Errorf("error removing Conf file %s: %q", path, err)
76+
if err := removeCacheFile(getKeyPath(key)); err != nil {
77+
return nil
78+
}
79+
return removeCacheFile(getOldKeyPath(key))
80+
}
81+
82+
// read content from the file in the provided path, returns nil, nil
83+
// if file not found
84+
func readCacheFile(path string) ([]byte, error) {
85+
data, err := os.ReadFile(path)
86+
if err != nil {
87+
if os.IsNotExist(err) {
88+
return nil, nil
89+
}
90+
return nil, fmt.Errorf("failed to read container data in the path(%q): %v", path, err)
91+
}
92+
return data, nil
93+
}
94+
95+
// remove file in the provided path, returns nil if file not found
96+
func removeCacheFile(path string) error {
97+
if err := os.RemoveAll(path); err != nil {
98+
return fmt.Errorf("failed to remove container data from the path(%q): %v", path, err)
6699
}
67100
return nil
68101
}
69102

70103
func getKeyPath(key string) string {
71-
return filepath.Join(DefaultCacheDir, key)
104+
return filepath.Join(rootDir, DefaultCacheDir, key)
105+
}
106+
107+
func getOldKeyPath(key string) string {
108+
return filepath.Join(rootDir, OldDefaultCacheDir, key)
72109
}

pkg/utils/cache_test.go

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright (c) 2024 CNI authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package utils
16+
17+
import (
18+
"os"
19+
"path/filepath"
20+
21+
. "github.com/onsi/ginkgo"
22+
. "github.com/onsi/gomega"
23+
)
24+
25+
type testConf struct {
26+
Data string `json:"data"`
27+
}
28+
29+
func writeToCacheDir(tmpDir, cacheDir, key string, data []byte) {
30+
d := filepath.Join(tmpDir, cacheDir)
31+
ExpectWithOffset(1, os.MkdirAll(d, 0700)).NotTo(HaveOccurred())
32+
ExpectWithOffset(1, os.WriteFile(filepath.Join(d, key), data, 0700)).NotTo(HaveOccurred())
33+
}
34+
35+
var _ = Describe("Utils", func() {
36+
Context("Cache", func() {
37+
var (
38+
tmpDir string
39+
err error
40+
)
41+
BeforeEach(func() {
42+
tmpDir, err = os.MkdirTemp("", "ovs-cni-cache-test*")
43+
rootDir = tmpDir
44+
Expect(err).NotTo(HaveOccurred())
45+
})
46+
AfterEach(func() {
47+
rootDir = ""
48+
Expect(os.RemoveAll(tmpDir)).NotTo(HaveOccurred())
49+
})
50+
It("should save data to the new cache path", func() {
51+
Expect(SaveCache("key1", testConf{Data: "test"})).NotTo(HaveOccurred())
52+
data, err := os.ReadFile(filepath.Join(tmpDir, "/var/lib/cni/ovs-cni/cache/key1"))
53+
Expect(err).NotTo(HaveOccurred())
54+
Expect(string(data)).To(Equal(`{"data":"test"}`))
55+
})
56+
It("should return data from the new cache dir", func() {
57+
origData := []byte(`{"data":"test"}`)
58+
writeToCacheDir(tmpDir, "/var/lib/cni/ovs-cni/cache", "key1", origData)
59+
data, err := ReadCache("key1")
60+
Expect(err).NotTo(HaveOccurred())
61+
Expect(data).To(Equal([]byte(`{"data":"test"}`)))
62+
})
63+
It("should return data from the old cache dir", func() {
64+
origData := []byte(`{"data":"test"}`)
65+
writeToCacheDir(tmpDir, "/tmp/ovscache", "key1", origData)
66+
data, err := ReadCache("key1")
67+
Expect(err).NotTo(HaveOccurred())
68+
Expect(data).To(Equal([]byte(`{"data":"test"}`)))
69+
})
70+
It("should return error if can't read data from new and old path", func() {
71+
data, err := ReadCache("key1")
72+
Expect(err).To(MatchError(ContainSubstring("not found")))
73+
Expect(data).To(BeNil())
74+
})
75+
It("should remove data from old and new path", func() {
76+
origData := []byte(`{"data":"test"}`)
77+
writeToCacheDir(tmpDir, "/var/lib/cni/ovs-cni/cache", "key1", origData)
78+
writeToCacheDir(tmpDir, "/tmp/ovscache", "key1", origData)
79+
Expect(CleanCache("key1")).NotTo(HaveOccurred())
80+
_, err := ReadCache("key1")
81+
Expect(err).To(MatchError(ContainSubstring("not found")))
82+
})
83+
It("should not return error when clean called for unknown key", func() {
84+
Expect(CleanCache("key1")).NotTo(HaveOccurred())
85+
})
86+
})
87+
})

pkg/utils/utils_suite_test.go

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) 2024 CNI authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package utils
16+
17+
import (
18+
"testing"
19+
20+
. "github.com/onsi/ginkgo"
21+
. "github.com/onsi/gomega"
22+
)
23+
24+
func TestUtils(t *testing.T) {
25+
RegisterFailHandler(Fail)
26+
RunSpecs(t, "Utils Suite")
27+
}

0 commit comments

Comments
 (0)