Skip to content

Commit a446c15

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

File tree

3 files changed

+104
-2
lines changed

3 files changed

+104
-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: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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+
"testing"
21+
)
22+
23+
func TestGetSnapshotID(t *testing.T) {
24+
testCases := []struct {
25+
name string
26+
inputPath string
27+
expectedIsSnapshot bool
28+
expectedSnapshotID string
29+
}{
30+
{
31+
name: "should recognize foo.snap as a valid snapshot with ID foo",
32+
inputPath: "foo.snap",
33+
expectedIsSnapshot: true,
34+
expectedSnapshotID: "foo",
35+
},
36+
{
37+
name: "should recognize baz.tar.gz as an invalid snapshot",
38+
inputPath: "baz.tar.gz",
39+
expectedIsSnapshot: false,
40+
expectedSnapshotID: "",
41+
},
42+
{
43+
name: "should recognize baz.tar.snap as a valid snapshot with ID baz.tar",
44+
inputPath: "baz.tar.snap",
45+
expectedIsSnapshot: true,
46+
expectedSnapshotID: "baz.tar",
47+
},
48+
{
49+
name: "should recognize baz.tar.snap.snap as a valid snapshot with ID baz.tar.snap",
50+
inputPath: "baz.tar.snap.snap",
51+
expectedIsSnapshot: true,
52+
expectedSnapshotID: "baz.tar.snap",
53+
},
54+
}
55+
56+
for _, tc := range testCases {
57+
t.Run(tc.name, func(t *testing.T) {
58+
actualIsSnapshot, actualSnapshotID := getSnapshotID(tc.inputPath)
59+
if actualIsSnapshot != tc.expectedIsSnapshot {
60+
t.Errorf("unexpected result for path %s, Want: %t, Got: %t", tc.inputPath, tc.expectedIsSnapshot, actualIsSnapshot)
61+
}
62+
if actualSnapshotID != tc.expectedSnapshotID {
63+
t.Errorf("unexpected snapshotID for path %s, Want: %s; Got :%s", tc.inputPath, tc.expectedSnapshotID, actualSnapshotID)
64+
}
65+
})
66+
}
67+
}

0 commit comments

Comments
 (0)