Skip to content

Commit ce42aad

Browse files
discover existing on-disk snapshots
Signed-off-by: Ashish Amarnath <[email protected]>
1 parent b44e56a commit ce42aad

File tree

3 files changed

+106
-2
lines changed

3 files changed

+106
-2
lines changed

pkg/hostpath/controllerserver.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,8 @@ func (cs *controllerServer) ListVolumes(ctx context.Context, req *csi.ListVolume
281281
}
282282

283283
// getSnapshotPath returns the full path to where the snapshot is stored
284-
func getSnapshotPath(snapshotId string) string {
285-
return filepath.Join(dataRoot, fmt.Sprintf("%s.snap", snapshotId))
284+
func getSnapshotPath(snapshotID string) string {
285+
return filepath.Join(dataRoot, fmt.Sprintf("%s%s", snapshotID, snapshotExt))
286286
}
287287

288288
// CreateSnapshot uses tar command to create snapshot for hostpath volume. The tar command can quickly create

pkg/hostpath/hostpath.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ import (
2020
"errors"
2121
"fmt"
2222
"io"
23+
"io/ioutil"
2324
"os"
2425
"path/filepath"
26+
"strings"
2527

2628
"github.com/golang/glog"
2729
"google.golang.org/grpc/codes"
@@ -87,6 +89,9 @@ const (
8789
// This can be ephemeral within the container or persisted if
8890
// backed by a Pod volume.
8991
dataRoot = "/csi-data-dir"
92+
93+
// Extension with which snapshot files will be saved.
94+
snapshotExt = ".snap"
9095
)
9196

9297
func init() {
@@ -127,12 +132,42 @@ func NewHostPathDriver(driverName, nodeID, endpoint string, ephemeral bool, maxV
127132
}, nil
128133
}
129134

135+
func getSnapshotID(file string) (bool, string) {
136+
glog.V(4).Infof("file: %s", file)
137+
// Files with .snap extension are volumesnapshot files.
138+
// e.g. foo.snap, foo.bar.snap
139+
if filepath.Ext(file) == snapshotExt {
140+
return true, strings.TrimSuffix(file, snapshotExt)
141+
}
142+
return false, ""
143+
}
144+
145+
func discoverExistingSnapshots() {
146+
glog.V(4).Infof("discovering existing snapshots in %s", dataRoot)
147+
files, err := ioutil.ReadDir(dataRoot)
148+
if err != nil {
149+
glog.Errorf("failed to discover snapshots under %s: %v", dataRoot, err)
150+
}
151+
for _, file := range files {
152+
isSnapshot, snapshotID := getSnapshotID(file.Name())
153+
if isSnapshot {
154+
glog.V(4).Infof("adding snapshot %s from file %s", snapshotID, file.Name())
155+
hostPathVolumeSnapshots[snapshotID] = hostPathSnapshot{
156+
Id: snapshotID,
157+
Path: file.Name(),
158+
ReadyToUse: true,
159+
}
160+
}
161+
}
162+
}
163+
130164
func (hp *hostPath) Run() {
131165
// Create GRPC servers
132166
hp.ids = NewIdentityServer(hp.name, hp.version)
133167
hp.ns = NewNodeServer(hp.nodeID, hp.ephemeral, hp.maxVolumesPerNode)
134168
hp.cs = NewControllerServer(hp.ephemeral, hp.nodeID)
135169

170+
discoverExistingSnapshots()
136171
s := NewNonBlockingGRPCServer()
137172
s.Start(hp.endpoint, hp.ids, hp.cs, hp.ns)
138173
s.Wait()

pkg/hostpath/hostpath_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package hostpath
18+
19+
import (
20+
"fmt"
21+
"testing"
22+
)
23+
24+
func TestGetSnapshotID(t *testing.T) {
25+
testCases := []struct {
26+
inputPath string
27+
expectedIsSnapshot bool
28+
expectedSnapshotID string
29+
}{
30+
{
31+
inputPath: "foo.snap",
32+
expectedIsSnapshot: true,
33+
expectedSnapshotID: "foo",
34+
},
35+
{
36+
inputPath: "foo/bar/baz.snap",
37+
expectedIsSnapshot: true,
38+
expectedSnapshotID: "baz",
39+
},
40+
{
41+
inputPath: "foo/bar/baz.tar.gz",
42+
expectedIsSnapshot: false,
43+
expectedSnapshotID: "",
44+
},
45+
{
46+
inputPath: "foo/bar/baz.tar.snap",
47+
expectedIsSnapshot: true,
48+
expectedSnapshotID: "baz.tar",
49+
},
50+
{
51+
inputPath: "foo/bar/baz.tar.snap.snap",
52+
expectedIsSnapshot: true,
53+
expectedSnapshotID: "baz.tar.snap",
54+
},
55+
}
56+
57+
for _, tc := range testCases {
58+
name := fmt.Sprintf("getSnapshotID(%s)", tc.inputPath)
59+
t.Run(name, func(t *testing.T) {
60+
actualIsSnapshot, actualSnapshotID := getSnapshotID(tc.inputPath)
61+
if actualIsSnapshot != tc.expectedIsSnapshot {
62+
t.Errorf("%s failed, unexpected result for path %s, Want: %t, Got: %t", name, tc.inputPath, tc.expectedIsSnapshot, actualIsSnapshot)
63+
}
64+
if actualSnapshotID != tc.expectedSnapshotID {
65+
t.Errorf("%s failed, unexpected snapshotID for path %s, Want: %s; Got :%s", name, tc.inputPath, tc.expectedSnapshotID, actualSnapshotID)
66+
}
67+
})
68+
}
69+
}

0 commit comments

Comments
 (0)