2018-12-19 14:26:16 +00:00
|
|
|
/*
|
2019-04-03 08:46:15 +00:00
|
|
|
Copyright 2018 The Ceph-CSI Authors.
|
2018-12-19 14:26:16 +00:00
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package util
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"path"
|
|
|
|
"path/filepath"
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
2019-02-04 13:05:43 +00:00
|
|
|
"k8s.io/klog"
|
2018-12-19 14:26:16 +00:00
|
|
|
)
|
|
|
|
|
2019-01-28 11:47:06 +00:00
|
|
|
// NodeCache to store metadata
|
2018-12-19 14:26:16 +00:00
|
|
|
type NodeCache struct {
|
|
|
|
BasePath string
|
2019-03-25 14:47:39 +00:00
|
|
|
CacheDir string
|
2018-12-19 14:26:16 +00:00
|
|
|
}
|
|
|
|
|
2019-01-29 05:49:16 +00:00
|
|
|
var errDec = errors.New("file not found")
|
|
|
|
|
2019-01-28 11:47:06 +00:00
|
|
|
// EnsureCacheDirectory creates cache directory if not present
|
2018-12-19 14:26:16 +00:00
|
|
|
func (nc *NodeCache) EnsureCacheDirectory(cacheDir string) error {
|
|
|
|
fullPath := path.Join(nc.BasePath, cacheDir)
|
|
|
|
if _, err := os.Stat(fullPath); os.IsNotExist(err) {
|
2019-01-28 19:55:10 +00:00
|
|
|
// #nosec
|
2018-12-19 14:26:16 +00:00
|
|
|
if err := os.Mkdir(fullPath, 0755); err != nil {
|
2019-02-20 14:04:30 +00:00
|
|
|
return errors.Wrapf(err, "node-cache: failed to create %s folder", fullPath)
|
2018-12-19 14:26:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-06-10 06:48:41 +00:00
|
|
|
// ForAll list the metadata in Nodecache and filters outs based on the pattern
|
2018-12-19 14:26:16 +00:00
|
|
|
func (nc *NodeCache) ForAll(pattern string, destObj interface{}, f ForAllFunc) error {
|
2019-03-25 14:47:39 +00:00
|
|
|
err := nc.EnsureCacheDirectory(nc.CacheDir)
|
2018-12-19 14:26:16 +00:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "node-cache: couldn't ensure cache directory exists")
|
|
|
|
}
|
2019-03-25 14:47:39 +00:00
|
|
|
files, err := ioutil.ReadDir(path.Join(nc.BasePath, nc.CacheDir))
|
2018-12-19 14:26:16 +00:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrapf(err, "node-cache: failed to read %s folder", nc.BasePath)
|
|
|
|
}
|
2019-06-10 06:48:41 +00:00
|
|
|
cachePath := path.Join(nc.BasePath, nc.CacheDir)
|
2018-12-19 14:26:16 +00:00
|
|
|
for _, file := range files {
|
2019-06-10 06:48:41 +00:00
|
|
|
err = decodeObj(cachePath, pattern, file, destObj)
|
2019-01-29 05:49:16 +00:00
|
|
|
if err == errDec {
|
2018-12-19 14:26:16 +00:00
|
|
|
continue
|
2019-01-29 05:49:16 +00:00
|
|
|
} else if err == nil {
|
|
|
|
if err = f(strings.TrimSuffix(file.Name(), filepath.Ext(file.Name()))); err != nil {
|
|
|
|
return err
|
2019-01-28 13:59:16 +00:00
|
|
|
}
|
2018-12-19 14:26:16 +00:00
|
|
|
}
|
2019-01-29 05:49:16 +00:00
|
|
|
return err
|
|
|
|
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-06-10 06:48:41 +00:00
|
|
|
func decodeObj(fpath, pattern string, file os.FileInfo, destObj interface{}) error {
|
2019-01-29 05:49:16 +00:00
|
|
|
match, err := regexp.MatchString(pattern, file.Name())
|
|
|
|
if err != nil || !match {
|
|
|
|
return errDec
|
|
|
|
}
|
|
|
|
if !strings.HasSuffix(file.Name(), ".json") {
|
|
|
|
return errDec
|
|
|
|
}
|
|
|
|
// #nosec
|
2019-06-10 06:48:41 +00:00
|
|
|
fp, err := os.Open(path.Join(fpath, file.Name()))
|
2019-01-29 05:49:16 +00:00
|
|
|
if err != nil {
|
2019-02-04 13:05:43 +00:00
|
|
|
klog.Infof("node-cache: open file: %s err %v", file.Name(), err)
|
2019-01-29 05:49:16 +00:00
|
|
|
return errDec
|
|
|
|
}
|
|
|
|
decoder := json.NewDecoder(fp)
|
|
|
|
if err = decoder.Decode(destObj); err != nil {
|
|
|
|
if err = fp.Close(); err != nil {
|
|
|
|
return errors.Wrapf(err, "failed to close file %s", file.Name())
|
|
|
|
|
2018-12-19 14:26:16 +00:00
|
|
|
}
|
2019-01-29 05:49:16 +00:00
|
|
|
return errors.Wrapf(err, "node-cache: couldn't decode file %s", file.Name())
|
2018-12-19 14:26:16 +00:00
|
|
|
}
|
|
|
|
return nil
|
2019-01-29 05:49:16 +00:00
|
|
|
|
2018-12-19 14:26:16 +00:00
|
|
|
}
|
|
|
|
|
2019-01-28 11:47:06 +00:00
|
|
|
// Create creates the metadata file in cache directory with identifier name
|
2018-12-19 14:26:16 +00:00
|
|
|
func (nc *NodeCache) Create(identifier string, data interface{}) error {
|
2019-03-25 14:47:39 +00:00
|
|
|
file := path.Join(nc.BasePath, nc.CacheDir, identifier+".json")
|
2018-12-19 14:26:16 +00:00
|
|
|
fp, err := os.Create(file)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrapf(err, "node-cache: failed to create metadata storage file %s\n", file)
|
|
|
|
}
|
2019-01-28 13:59:16 +00:00
|
|
|
|
|
|
|
defer func() {
|
|
|
|
if err = fp.Close(); err != nil {
|
2019-02-04 13:05:43 +00:00
|
|
|
klog.Warningf("failed to close file:%s %v", fp.Name(), err)
|
2019-01-28 13:59:16 +00:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2018-12-19 14:26:16 +00:00
|
|
|
encoder := json.NewEncoder(fp)
|
|
|
|
if err = encoder.Encode(data); err != nil {
|
|
|
|
return errors.Wrapf(err, "node-cache: failed to encode metadata for file: %s\n", file)
|
|
|
|
}
|
2019-02-04 13:05:43 +00:00
|
|
|
klog.V(4).Infof("node-cache: successfully saved metadata into file: %s\n", file)
|
2018-12-19 14:26:16 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-01-28 11:47:06 +00:00
|
|
|
// Get retrieves the metadata from cache directory with identifier name
|
2018-12-19 14:26:16 +00:00
|
|
|
func (nc *NodeCache) Get(identifier string, data interface{}) error {
|
2019-03-25 14:47:39 +00:00
|
|
|
file := path.Join(nc.BasePath, nc.CacheDir, identifier+".json")
|
2019-01-28 19:55:10 +00:00
|
|
|
// #nosec
|
2018-12-19 14:26:16 +00:00
|
|
|
fp, err := os.Open(file)
|
|
|
|
if err != nil {
|
2019-02-25 17:05:20 +00:00
|
|
|
if os.IsNotExist(errors.Cause(err)) {
|
|
|
|
return &CacheEntryNotFound{err}
|
|
|
|
}
|
|
|
|
|
2018-12-19 14:26:16 +00:00
|
|
|
return errors.Wrapf(err, "node-cache: open error for %s", file)
|
|
|
|
}
|
2019-01-28 13:59:16 +00:00
|
|
|
|
|
|
|
defer func() {
|
|
|
|
if err = fp.Close(); err != nil {
|
2019-02-04 13:05:43 +00:00
|
|
|
klog.Warningf("failed to close file:%s %v", fp.Name(), err)
|
2019-01-28 13:59:16 +00:00
|
|
|
}
|
|
|
|
}()
|
2018-12-19 14:26:16 +00:00
|
|
|
|
|
|
|
decoder := json.NewDecoder(fp)
|
|
|
|
if err = decoder.Decode(data); err != nil {
|
|
|
|
return errors.Wrap(err, "rbd: decode error")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-01-28 11:47:06 +00:00
|
|
|
// Delete deletes the metadata file from cache directory with identifier name
|
2018-12-19 14:26:16 +00:00
|
|
|
func (nc *NodeCache) Delete(identifier string) error {
|
2019-03-25 14:47:39 +00:00
|
|
|
file := path.Join(nc.BasePath, nc.CacheDir, identifier+".json")
|
2018-12-19 14:26:16 +00:00
|
|
|
err := os.Remove(file)
|
|
|
|
if err != nil {
|
2019-12-17 09:07:46 +00:00
|
|
|
if os.IsNotExist(err) {
|
2019-02-20 14:04:30 +00:00
|
|
|
klog.V(4).Infof("node-cache: cannot delete missing metadata storage file %s, assuming it's already deleted", file)
|
|
|
|
return nil
|
2018-12-19 14:26:16 +00:00
|
|
|
}
|
2019-02-20 14:04:30 +00:00
|
|
|
|
|
|
|
return errors.Wrapf(err, "node-cache: error removing file %s", file)
|
|
|
|
|
2018-12-19 14:26:16 +00:00
|
|
|
}
|
2019-02-04 13:05:43 +00:00
|
|
|
klog.V(4).Infof("node-cache: successfully deleted metadata storage file at: %+v\n", file)
|
2018-12-19 14:26:16 +00:00
|
|
|
return nil
|
|
|
|
}
|