Skip to content
This repository was archived by the owner on Mar 16, 2021. It is now read-only.

Commit 07864ee

Browse files
committed
hostpaht snapshot implemention
1 parent d82cde8 commit 07864ee

File tree

14 files changed

+205
-14
lines changed

14 files changed

+205
-14
lines changed

pkg/cinder/deploy/kubernetes/csi-attacher-cinderplugin.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ spec:
3030
serviceAccount: csi-attacher
3131
containers:
3232
- name: csi-attacher
33-
image: quay.io/k8scsi/csi-attacher:v0.2.0
33+
image: quay.io/k8scsi/csi-attacher:v0.3.0
3434
args:
3535
- "--v=5"
3636
- "--csi-address=$(ADDRESS)"

pkg/cinder/deploy/kubernetes/csi-nodeplugin-cinderplugin.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ spec:
1818
hostNetwork: true
1919
containers:
2020
- name: driver-registrar
21-
image: quay.io/k8scsi/driver-registrar:v0.2.0
21+
image: quay.io/k8scsi/driver-registrar:v0.3.0
2222
args:
2323
- "--v=5"
2424
- "--csi-address=$(ADDRESS)"

pkg/cinder/deploy/kubernetes/csi-provisioner-cinderplugin.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ spec:
3030
serviceAccount: csi-provisioner
3131
containers:
3232
- name: csi-provisioner
33-
image: quay.io/k8scsi/csi-provisioner:v0.2.0
33+
image: quay.io/k8scsi/csi-provisioner:v0.3.0
3434
args:
3535
- "--provisioner=csi-cinderplugin"
3636
- "--csi-address=$(ADDRESS)"

pkg/cinder/driver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ const (
4242
)
4343

4444
var (
45-
version = "0.2.0"
45+
version = "0.3.0"
4646
)
4747

4848
func NewDriver(nodeID, endpoint string, cloudconfig string) *driver {

pkg/csi-common/controllerserver-default.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,15 @@ func (cs *DefaultControllerServer) ControllerGetCapabilities(ctx context.Context
8585
Capabilities: cs.Driver.cap,
8686
}, nil
8787
}
88+
89+
func (cs *DefaultControllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateSnapshotRequest) (*csi.CreateSnapshotResponse, error) {
90+
return nil, status.Error(codes.Unimplemented, "")
91+
}
92+
93+
func (cs *DefaultControllerServer) DeleteSnapshot(ctx context.Context, req *csi.DeleteSnapshotRequest) (*csi.DeleteSnapshotResponse, error) {
94+
return nil, status.Error(codes.Unimplemented, "")
95+
}
96+
97+
func (cs *DefaultControllerServer) ListSnapshots(ctx context.Context, req *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) {
98+
return nil, status.Error(codes.Unimplemented, "")
99+
}

pkg/csi-common/driver_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const (
3131
)
3232

3333
var (
34-
vendorVersion = "0.2.0"
34+
vendorVersion = "0.3.0"
3535
)
3636

3737
func NewFakeDriver() *CSIDriver {

pkg/csi-common/nodeserver-default.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,7 @@ func (ns *DefaultNodeServer) NodeGetCapabilities(ctx context.Context, req *csi.N
5959
},
6060
}, nil
6161
}
62+
63+
func (ns *DefaultNodeServer) NodeGetInfo(context.Context, *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) {
64+
return nil, status.Error(codes.Unimplemented, "")
65+
}

pkg/flexadapter/flexadapter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ type flexAdapter struct {
3838
}
3939

4040
var (
41-
version = "0.2.0"
41+
version = "0.3.0"
4242
)
4343

4444
func New() *flexAdapter {

pkg/hostpath/controllerserver.go

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package hostpath
1919
import (
2020
"fmt"
2121
"os"
22+
"time"
2223

2324
"github.com/golang/glog"
2425
"github.com/pborman/uuid"
@@ -28,11 +29,13 @@ import (
2829

2930
"github.com/container-storage-interface/spec/lib/go/csi/v0"
3031
"github.com/kubernetes-csi/drivers/pkg/csi-common"
32+
utilexec "k8s.io/utils/exec"
3133
)
3234

3335
const (
3436
deviceID = "deviceID"
3537
provisionRoot = "/tmp/"
38+
snapshotRoot = "/tmp/"
3639
maxStorageCapacity = tib
3740
)
3841

@@ -136,3 +139,151 @@ func (cs *controllerServer) ValidateVolumeCapabilities(ctx context.Context, req
136139
}
137140
return &csi.ValidateVolumeCapabilitiesResponse{Supported: true, Message: ""}, nil
138141
}
142+
143+
// CreateSnapshot uses tar command to create snapshot for hostpath volume. The tar command can quickly create
144+
// archives of entire directories. The host image must have "tar" binaries in /bin, /usr/sbin, or /usr/bin.
145+
func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateSnapshotRequest) (*csi.CreateSnapshotResponse, error) {
146+
if err := cs.Driver.ValidateControllerServiceRequest(csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT); err != nil {
147+
glog.V(3).Infof("invalid create snapshot req: %v", req)
148+
return nil, err
149+
}
150+
151+
// Check arguments
152+
if len(req.GetSourceVolumeId()) == 0 {
153+
return nil, status.Error(codes.InvalidArgument, "SourceVolumeId missing in request")
154+
}
155+
if len(req.GetName()) == 0 {
156+
return nil, status.Error(codes.InvalidArgument, "Name missing in request")
157+
}
158+
159+
// Need to check for already existing snapshot name, and if found check for the
160+
// requested sourceVolumeId and sourceVolumeId of snapshot that has been created.
161+
if exSnap, err := getSnapshotByName(req.GetName()); err == nil {
162+
// Since err is nil, it means the snapshot with the same name already exists need
163+
// to check if the sourceVolumeId of existing snapshot is the same as in new request.
164+
if exSnap.VolID == req.GetSourceVolumeId() {
165+
// same snapshot has been created.
166+
return &csi.CreateSnapshotResponse{
167+
Snapshot: &csi.Snapshot{
168+
Id: exSnap.Id,
169+
SourceVolumeId: exSnap.VolID,
170+
CreatedAt: exSnap.CreateAt,
171+
Status: exSnap.Status,
172+
},
173+
}, nil
174+
}
175+
return nil, status.Error(codes.AlreadyExists, fmt.Sprintf("snapshot with the same name: %s but with different SourceVolumeId already exist", req.GetName()))
176+
}
177+
178+
volumeID := req.GetSourceVolumeId()
179+
hostPathVolume, ok := hostPathVolumes[volumeID]
180+
if !ok {
181+
return nil, status.Error(codes.Internal, "volumeID is not exist")
182+
}
183+
184+
snapshotID := uuid.NewUUID().String()
185+
createAt := time.Now().UnixNano()
186+
volPath := hostPathVolume.VolPath
187+
file := snapshotRoot + snapshotID + ".tgz"
188+
args := []string{"czf", file, "-C", volPath, "."}
189+
executor := utilexec.New()
190+
out, err := executor.Command("tar", args...).CombinedOutput()
191+
if err != nil {
192+
return nil, status.Error(codes.Internal, fmt.Sprintf("failed create snapshot: %v: %s", err, out))
193+
}
194+
195+
glog.V(4).Infof("create volume snapshot %s", file)
196+
snapshot := hostPathSnapshot{}
197+
snapshot.Name = req.GetName()
198+
snapshot.Id = snapshotID
199+
snapshot.VolID = volumeID
200+
snapshot.Path = file
201+
snapshot.CreateAt = createAt
202+
snapshot.Status = &csi.SnapshotStatus{
203+
Type: csi.SnapshotStatus_READY,
204+
Details: fmt.Sprint("Successfully create snapshot"),
205+
}
206+
207+
hostPathVolumeSnapshots[snapshotID] = snapshot
208+
209+
return &csi.CreateSnapshotResponse{
210+
Snapshot: &csi.Snapshot{
211+
Id: snapshot.Id,
212+
SourceVolumeId: snapshot.VolID,
213+
CreatedAt: snapshot.CreateAt,
214+
Status: snapshot.Status,
215+
},
216+
}, nil
217+
}
218+
219+
func (cs *controllerServer) DeleteSnapshot(ctx context.Context, req *csi.DeleteSnapshotRequest) (*csi.DeleteSnapshotResponse, error) {
220+
// Check arguments
221+
if len(req.GetSnapshotId()) == 0 {
222+
return nil, status.Error(codes.InvalidArgument, "Snapshot ID missing in request")
223+
}
224+
225+
if err := cs.Driver.ValidateControllerServiceRequest(csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT); err != nil {
226+
glog.V(3).Infof("invalid delete snapshot req: %v", req)
227+
return nil, err
228+
}
229+
snapshotID := req.SnapshotId
230+
glog.V(4).Infof("deleting volume %s", snapshotID)
231+
path := snapshotRoot + snapshotID + ".tgz"
232+
os.RemoveAll(path)
233+
delete(hostPathVolumeSnapshots, snapshotID)
234+
return &csi.DeleteSnapshotResponse{}, nil
235+
}
236+
237+
func (cs *controllerServer) ListSnapshots(ctx context.Context, req *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) {
238+
if err := cs.Driver.ValidateControllerServiceRequest(csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS); err != nil {
239+
glog.V(3).Infof("invalid list snapshot req: %v", req)
240+
return nil, err
241+
}
242+
243+
var snapshots []hostPathSnapshot
244+
245+
// case 1: SnapshotId is not empty, return snapshots that match the snapshot id.
246+
if len(req.GetSnapshotId()) != 0 {
247+
snapshotID := req.SnapshotId
248+
if snapshot, ok := hostPathVolumeSnapshots[snapshotID]; ok {
249+
snapshots = append(snapshots, snapshot)
250+
// jump to the result processing.
251+
goto result
252+
}
253+
}
254+
255+
// case 2: SourceVolumeId is not empty, return snapshots that match the source volume id.
256+
if len(req.SourceVolumeId) != 0 {
257+
for _, snapshot := range hostPathVolumeSnapshots {
258+
if snapshot.VolID == req.SourceVolumeId {
259+
snapshots = append(snapshots, snapshot)
260+
// jump to the result processing.
261+
goto result
262+
}
263+
}
264+
}
265+
266+
// case 3: no parameter is set, so we return all the snapshots.
267+
for _, snapshot := range hostPathVolumeSnapshots {
268+
snapshots = append(snapshots, snapshot)
269+
}
270+
271+
result:
272+
var entries []*csi.ListSnapshotsResponse_Entry
273+
for _, snap := range snapshots {
274+
entries = append(entries, &csi.ListSnapshotsResponse_Entry{
275+
Snapshot: &csi.Snapshot{
276+
Id: snap.Id,
277+
SourceVolumeId: snap.VolID,
278+
CreatedAt: snap.CreateAt,
279+
Status: snap.Status,
280+
},
281+
})
282+
}
283+
284+
rsp := &csi.ListSnapshotsResponse{
285+
Entries: entries,
286+
}
287+
288+
return rsp, nil
289+
}

pkg/hostpath/hostpath.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,21 @@ type hostPathVolume struct {
5252
VolPath string `json:"volPath"`
5353
}
5454

55+
type hostPathSnapshot struct {
56+
Name string `json:"name"`
57+
Id string `json:"id"`
58+
VolID string `json:"volID"`
59+
Path string `json:"path"`
60+
CreateAt int64 `json:"createAt"`
61+
Status *csi.SnapshotStatus `json:"status"`
62+
}
63+
5564
var hostPathVolumes map[string]hostPathVolume
65+
var hostPathVolumeSnapshots map[string]hostPathSnapshot
5666

5767
var (
5868
hostPathDriver *hostPath
59-
vendorVersion = "0.2.0"
69+
vendorVersion = "0.3.0"
6070
)
6171

6272
func init() {
@@ -93,7 +103,12 @@ func (hp *hostPath) Run(driverName, nodeID, endpoint string) {
93103
if hp.driver == nil {
94104
glog.Fatalln("Failed to initialize CSI Driver.")
95105
}
96-
hp.driver.AddControllerServiceCapabilities([]csi.ControllerServiceCapability_RPC_Type{csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME})
106+
hp.driver.AddControllerServiceCapabilities(
107+
[]csi.ControllerServiceCapability_RPC_Type{
108+
csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME,
109+
csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT,
110+
csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS,
111+
})
97112
hp.driver.AddVolumeCapabilityAccessModes([]csi.VolumeCapability_AccessMode_Mode{csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER})
98113

99114
// Create GRPC servers
@@ -121,3 +136,12 @@ func getVolumeByName(volName string) (hostPathVolume, error) {
121136
}
122137
return hostPathVolume{}, fmt.Errorf("volume name %s does not exit in the volumes list", volName)
123138
}
139+
140+
func getSnapshotByName(name string) (hostPathSnapshot, error) {
141+
for _, snapshot := range hostPathVolumeSnapshots {
142+
if snapshot.Name == name {
143+
return snapshot, nil
144+
}
145+
}
146+
return hostPathSnapshot{}, fmt.Errorf("snapshot name %s does not exit in the snapshots list", name)
147+
}

0 commit comments

Comments
 (0)