diff --git a/pkg/kubelet/dockershim/checkpoint_store.go b/pkg/kubelet/dockershim/checkpoint_store.go deleted file mode 100644 index b8160bbd9bd..00000000000 --- a/pkg/kubelet/dockershim/checkpoint_store.go +++ /dev/null @@ -1,156 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -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 dockershim - -import ( - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "regexp" - "strings" - - "k8s.io/kubernetes/pkg/kubelet/dockershim/errors" -) - -const ( - tmpPrefix = "." - tmpSuffix = ".tmp" - keyMaxLength = 250 -) - -var keyRegex = regexp.MustCompile("^[a-zA-Z0-9]+$") - -// CheckpointStore provides the interface for checkpoint storage backend. -// CheckpointStore must be thread-safe -type CheckpointStore interface { - // key must contain one or more characters in [A-Za-z0-9] - // Write persists a checkpoint with key - Write(key string, data []byte) error - // Read retrieves a checkpoint with key - // Read must return CheckpointNotFoundError if checkpoint is not found - Read(key string) ([]byte, error) - // Delete deletes a checkpoint with key - // Delete must not return error if checkpoint does not exist - Delete(key string) error - // List lists all keys of existing checkpoints - List() ([]string, error) -} - -// FileStore is an implementation of CheckpointStore interface which stores checkpoint in files. -type FileStore struct { - // path to the base directory for storing checkpoint files - path string -} - -func NewFileStore(path string) (CheckpointStore, error) { - if err := ensurePath(path); err != nil { - return nil, err - } - return &FileStore{path: path}, nil -} - -// writeFileAndSync is copied from ioutil.WriteFile, with the extra File.Sync -// at the end to ensure file is written on the disk. -func writeFileAndSync(filename string, data []byte, perm os.FileMode) error { - f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) - if err != nil { - return err - } - n, err := f.Write(data) - if err == nil && n < len(data) { - err = io.ErrShortWrite - } - if err == nil { - // Only sync if the Write completed successfully. - err = f.Sync() - } - if err1 := f.Close(); err == nil { - err = err1 - } - return err -} - -func (fstore *FileStore) Write(key string, data []byte) error { - if err := validateKey(key); err != nil { - return err - } - if err := ensurePath(fstore.path); err != nil { - return err - } - tmpfile := filepath.Join(fstore.path, fmt.Sprintf("%s%s%s", tmpPrefix, key, tmpSuffix)) - if err := writeFileAndSync(tmpfile, data, 0644); err != nil { - return err - } - return os.Rename(tmpfile, fstore.getCheckpointPath(key)) -} - -func (fstore *FileStore) Read(key string) ([]byte, error) { - if err := validateKey(key); err != nil { - return nil, err - } - bytes, err := ioutil.ReadFile(fstore.getCheckpointPath(key)) - if os.IsNotExist(err) { - return bytes, errors.CheckpointNotFoundError - } - return bytes, err -} - -func (fstore *FileStore) Delete(key string) error { - if err := validateKey(key); err != nil { - return err - } - if err := os.Remove(fstore.getCheckpointPath(key)); err != nil && !os.IsNotExist(err) { - return err - } - return nil -} - -func (fstore *FileStore) List() ([]string, error) { - keys := make([]string, 0) - files, err := ioutil.ReadDir(fstore.path) - if err != nil { - return keys, err - } - for _, f := range files { - if !strings.HasPrefix(f.Name(), tmpPrefix) { - keys = append(keys, f.Name()) - } - } - return keys, nil -} - -func (fstore *FileStore) getCheckpointPath(key string) string { - return filepath.Join(fstore.path, key) -} - -// ensurePath creates input directory if it does not exist -func ensurePath(path string) error { - if _, err := os.Stat(path); err != nil { - // MkdirAll returns nil if directory already exists - return os.MkdirAll(path, 0755) - } - return nil -} - -func validateKey(key string) error { - if len(key) <= keyMaxLength && keyRegex.MatchString(key) { - return nil - } - return fmt.Errorf("checkpoint key %q is not valid.", key) -} diff --git a/pkg/kubelet/dockershim/checkpoint_store_test.go b/pkg/kubelet/dockershim/checkpoint_store_test.go deleted file mode 100644 index 97d7a5a239d..00000000000 --- a/pkg/kubelet/dockershim/checkpoint_store_test.go +++ /dev/null @@ -1,158 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -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 dockershim - -import ( - "io/ioutil" - "os" - "sort" - "testing" - - "github.com/stretchr/testify/assert" - "k8s.io/kubernetes/pkg/kubelet/dockershim/errors" -) - -func TestFileStore(t *testing.T) { - path, err := ioutil.TempDir("", "FileStore") - assert.NoError(t, err) - defer cleanUpTestPath(t, path) - store, err := NewFileStore(path) - assert.NoError(t, err) - - Checkpoints := []struct { - key string - data string - expectErr bool - }{ - { - "id1", - "data1", - false, - }, - { - "id2", - "data2", - false, - }, - { - "/id1", - "data1", - true, - }, - { - ".id1", - "data1", - true, - }, - { - " ", - "data2", - true, - }, - { - "___", - "data2", - true, - }, - } - - // Test Add Checkpoint - for _, c := range Checkpoints { - _, err = store.Read(c.key) - assert.Error(t, err) - - err = store.Write(c.key, []byte(c.data)) - if c.expectErr { - assert.Error(t, err) - continue - } else { - assert.NoError(t, err) - } - - // Test Read Checkpoint - data, err := store.Read(c.key) - assert.NoError(t, err) - assert.Equal(t, string(data), c.data) - } - - // Test list checkpoints. - keys, err := store.List() - assert.NoError(t, err) - sort.Strings(keys) - assert.Equal(t, keys, []string{"id1", "id2"}) - - // Test Delete Checkpoint - for _, c := range Checkpoints { - if c.expectErr { - continue - } - - err = store.Delete(c.key) - assert.NoError(t, err) - _, err = store.Read(c.key) - assert.EqualValues(t, errors.CheckpointNotFoundError, err) - } - - // Test delete non existed checkpoint - err = store.Delete("id1") - assert.NoError(t, err) - - // Test list checkpoints. - keys, err = store.List() - assert.NoError(t, err) - assert.Equal(t, len(keys), 0) -} - -func TestIsValidKey(t *testing.T) { - testcases := []struct { - key string - valid bool - }{ - { - " ", - false, - }, - { - "/foo/bar", - false, - }, - { - ".foo", - false, - }, - { - "a78768279290d33d0b82eaea43cb8346f500057cb5bd250e88c97a5585385d66", - true, - }, - } - - for _, tc := range testcases { - if tc.valid { - assert.NoError(t, validateKey(tc.key)) - } else { - assert.Error(t, validateKey(tc.key)) - } - } -} - -func cleanUpTestPath(t *testing.T, path string) { - if _, err := os.Stat(path); !os.IsNotExist(err) { - if err := os.RemoveAll(path); err != nil { - assert.NoError(t, err, "Failed to delete test directory: %v", err) - } - } -} diff --git a/pkg/kubelet/dockershim/docker_checkpoint.go b/pkg/kubelet/dockershim/docker_checkpoint.go index 6ad1d794169..0b384d037dd 100644 --- a/pkg/kubelet/dockershim/docker_checkpoint.go +++ b/pkg/kubelet/dockershim/docker_checkpoint.go @@ -24,6 +24,8 @@ import ( "github.com/golang/glog" "k8s.io/kubernetes/pkg/kubelet/dockershim/errors" + utilstore "k8s.io/kubernetes/pkg/kubelet/util/store" + utilfs "k8s.io/kubernetes/pkg/util/filesystem" hashutil "k8s.io/kubernetes/pkg/util/hash" ) @@ -82,11 +84,11 @@ type CheckpointHandler interface { // PersistentCheckpointHandler is an implementation of CheckpointHandler. It persists checkpoint in CheckpointStore type PersistentCheckpointHandler struct { - store CheckpointStore + store utilstore.Store } func NewPersistentCheckpointHandler(dockershimRootDir string) (CheckpointHandler, error) { - fstore, err := NewFileStore(filepath.Join(dockershimRootDir, sandboxCheckpointDir)) + fstore, err := utilstore.NewFileStore(filepath.Join(dockershimRootDir, sandboxCheckpointDir), utilfs.DefaultFs{}) if err != nil { return nil, err }