Skip to content

Commit ac1ccd7

Browse files
authored
Merge pull request #10 from kfox1111/ephemeral
Ephemeral support
2 parents a6ba7d0 + 065acbe commit ac1ccd7

File tree

4 files changed

+113
-44
lines changed

4 files changed

+113
-44
lines changed

cmd/hostpathplugin/main.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ var (
3333
endpoint = flag.String("endpoint", "unix://tmp/csi.sock", "CSI endpoint")
3434
driverName = flag.String("drivername", "csi-hostpath", "name of the driver")
3535
nodeID = flag.String("nodeid", "", "node id")
36+
ephemeral = flag.Bool("ephemeral", false, "deploy in ephemeral mode")
3637
showVersion = flag.Bool("version", false, "Show version.")
3738
// Set by the build process
3839
version = ""
@@ -52,7 +53,7 @@ func main() {
5253
}
5354

5455
func handle() {
55-
driver, err := hostpath.NewHostPathDriver(*driverName, *nodeID, *endpoint, version)
56+
driver, err := hostpath.NewHostPathDriver(*driverName, *nodeID, *endpoint, version, *ephemeral)
5657
if err != nil {
5758
fmt.Printf("Failed to initialize driver: %s", err.Error())
5859
os.Exit(1)

pkg/hostpath/controllerserver.go

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,10 @@ type controllerServer struct {
5454
caps []*csi.ControllerServiceCapability
5555
}
5656

57-
func NewControllerServer() *controllerServer {
57+
func NewControllerServer(ephemeral bool) *controllerServer {
58+
if ephemeral {
59+
return &controllerServer{caps: getControllerServiceCapabilities(nil)}
60+
}
5861
return &controllerServer{
5962
caps: getControllerServiceCapabilities(
6063
[]csi.ControllerServiceCapability_RPC_Type{
@@ -110,6 +113,12 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
110113
requestedAccessType = mountAccess
111114
}
112115

116+
// Check for maximum available capacity
117+
capacity := int64(req.GetCapacityRange().GetRequiredBytes())
118+
if capacity >= maxStorageCapacity {
119+
return nil, status.Errorf(codes.OutOfRange, "Requested capacity %d exceeds maximum allowed %d", capacity, maxStorageCapacity)
120+
}
121+
113122
// Need to check for already existing volume name, and if found
114123
// check for the requested capacity and already allocated capacity
115124
if exVol, err := getVolumeByName(req.GetName()); err == nil {
@@ -129,17 +138,11 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
129138
}
130139
return nil, status.Error(codes.AlreadyExists, fmt.Sprintf("Volume with the same name: %s but with different size already exist", req.GetName()))
131140
}
132-
// Check for maximum available capacity
133-
capacity := int64(req.GetCapacityRange().GetRequiredBytes())
134-
if capacity >= maxStorageCapacity {
135-
return nil, status.Errorf(codes.OutOfRange, "Requested capacity %d exceeds maximum allowed %d", capacity, maxStorageCapacity)
136-
}
137141

138142
volumeID := uuid.NewUUID().String()
139-
path := provisionRoot + volumeID
143+
path := getVolumePath(volumeID)
140144

141-
switch requestedAccessType {
142-
case blockAccess:
145+
if requestedAccessType == blockAccess {
143146
executor := utilexec.New()
144147
size := fmt.Sprintf("%dM", capacity/mib)
145148
// Create a block file.
@@ -160,14 +163,14 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
160163
}
161164
return nil, status.Error(codes.Internal, fmt.Sprintf("failed to attach device: %v", err))
162165
}
163-
case mountAccess:
164-
err := os.MkdirAll(path, 0777)
165-
if err != nil {
166-
glog.V(3).Infof("failed to create volume: %v", err)
167-
return nil, err
168-
}
169166
}
170167

168+
vol, err := createHostpathVolume(volumeID, req.GetName(), capacity, requestedAccessType)
169+
if err != nil {
170+
return nil, status.Error(codes.Internal, fmt.Sprintf("failed to create volume: %s", err))
171+
}
172+
glog.V(4).Infof("created volume %s at path %s", vol.VolID, vol.VolPath)
173+
171174
if req.GetVolumeContentSource() != nil {
172175
contentSource := req.GetVolumeContentSource()
173176
if contentSource.GetSnapshot() != nil {
@@ -188,14 +191,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
188191
}
189192
}
190193
}
191-
glog.V(4).Infof("create volume %s", path)
192-
hostPathVol := hostPathVolume{}
193-
hostPathVol.VolName = req.GetName()
194-
hostPathVol.VolID = volumeID
195-
hostPathVol.VolSize = capacity
196-
hostPathVol.VolPath = path
197-
hostPathVol.VolAccessType = requestedAccessType
198-
hostPathVolumes[volumeID] = hostPathVol
194+
199195
return &csi.CreateVolumeResponse{
200196
Volume: &csi.Volume{
201197
VolumeId: volumeID,
@@ -228,7 +224,7 @@ func (cs *controllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol
228224

229225
volPathHandler := volumepathhandler.VolumePathHandler{}
230226
// Get the associated loop device.
231-
device, err := volPathHandler.GetLoopDevice(provisionRoot + vol.VolID)
227+
device, err := volPathHandler.GetLoopDevice(getVolumePath(vol.VolID))
232228
if err != nil {
233229
return nil, status.Error(codes.Internal, fmt.Sprintf("failed to get the loop device: %v", err))
234230
}
@@ -242,8 +238,12 @@ func (cs *controllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol
242238
}
243239
}
244240

245-
os.RemoveAll(vol.VolPath)
246-
delete(hostPathVolumes, vol.VolID)
241+
if err := deleteHostpathVolume(vol.VolID); err != nil && !os.IsNotExist(err) {
242+
return nil, status.Error(codes.Internal, fmt.Sprintf("failed to delete volume: %s", err))
243+
}
244+
245+
glog.V(4).Infof("volume deleted ok: %s", vol.VolID)
246+
247247
return &csi.DeleteVolumeResponse{}, nil
248248
}
249249

pkg/hostpath/hostpath.go

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package hostpath
1818

1919
import (
2020
"fmt"
21+
"os"
2122

2223
"github.com/golang/glog"
2324

@@ -34,10 +35,11 @@ const (
3435
)
3536

3637
type hostPath struct {
37-
name string
38-
nodeID string
39-
version string
40-
endpoint string
38+
name string
39+
nodeID string
40+
version string
41+
endpoint string
42+
ephemeral bool
4143

4244
ids *identityServer
4345
ns *nodeServer
@@ -74,7 +76,7 @@ func init() {
7476
hostPathVolumeSnapshots = map[string]hostPathSnapshot{}
7577
}
7678

77-
func NewHostPathDriver(driverName, nodeID, endpoint, version string) (*hostPath, error) {
79+
func NewHostPathDriver(driverName, nodeID, endpoint, version string, ephemeral bool) (*hostPath, error) {
7880
if driverName == "" {
7981
return nil, fmt.Errorf("No driver name provided")
8082
}
@@ -94,19 +96,19 @@ func NewHostPathDriver(driverName, nodeID, endpoint, version string) (*hostPath,
9496
glog.Infof("Version: %s", vendorVersion)
9597

9698
return &hostPath{
97-
name: driverName,
98-
version: vendorVersion,
99-
nodeID: nodeID,
100-
endpoint: endpoint,
99+
name: driverName,
100+
version: vendorVersion,
101+
nodeID: nodeID,
102+
endpoint: endpoint,
103+
ephemeral: ephemeral,
101104
}, nil
102105
}
103106

104107
func (hp *hostPath) Run() {
105-
106108
// Create GRPC servers
107109
hp.ids = NewIdentityServer(hp.name, hp.version)
108-
hp.ns = NewNodeServer(hp.nodeID)
109-
hp.cs = NewControllerServer()
110+
hp.ns = NewNodeServer(hp.nodeID, hp.ephemeral)
111+
hp.cs = NewControllerServer(hp.ephemeral)
110112

111113
s := NewNonBlockingGRPCServer()
112114
s.Start(hp.endpoint, hp.ids, hp.cs, hp.ns)
@@ -137,3 +139,40 @@ func getSnapshotByName(name string) (hostPathSnapshot, error) {
137139
}
138140
return hostPathSnapshot{}, fmt.Errorf("snapshot name %s does not exit in the snapshots list", name)
139141
}
142+
143+
// getVolumePath returs the canonical path for hostpath volume
144+
func getVolumePath(volID string) string {
145+
return fmt.Sprintf("%s/%s", provisionRoot, volID)
146+
}
147+
148+
// createVolume create the directory for the hostpath volume.
149+
// It returns the volume path or err if one occurs.
150+
func createHostpathVolume(volID, name string, cap int64, volAccessType accessType) (*hostPathVolume, error) {
151+
path := getVolumePath(volID)
152+
if volAccessType == mountAccess {
153+
err := os.MkdirAll(path, 0777)
154+
if err != nil {
155+
return nil, err
156+
}
157+
}
158+
159+
hostpathVol := hostPathVolume{
160+
VolID: volID,
161+
VolName: name,
162+
VolSize: cap,
163+
VolPath: path,
164+
VolAccessType: volAccessType,
165+
}
166+
hostPathVolumes[volID] = hostpathVol
167+
return &hostpathVol, nil
168+
}
169+
170+
// deleteVolume deletes the directory for the hostpath volume.
171+
func deleteHostpathVolume(volID string) error {
172+
path := getVolumePath(volID)
173+
if err := os.RemoveAll(path); err != nil {
174+
return err
175+
}
176+
delete(hostPathVolumes, volID)
177+
return nil
178+
}

pkg/hostpath/nodeserver.go

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

2324
"github.com/golang/glog"
2425
"golang.org/x/net/context"
@@ -31,12 +32,14 @@ import (
3132
)
3233

3334
type nodeServer struct {
34-
nodeID string
35+
nodeID string
36+
ephemeral bool
3537
}
3638

37-
func NewNodeServer(nodeId string) *nodeServer {
39+
func NewNodeServer(nodeId string, ephemeral bool) *nodeServer {
3840
return &nodeServer{
39-
nodeID: nodeId,
41+
nodeID: nodeId,
42+
ephemeral: ephemeral,
4043
}
4144
}
4245

@@ -60,6 +63,18 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
6063
return nil, status.Error(codes.InvalidArgument, "cannot have both block and mount access type")
6164
}
6265

66+
// if ephemeral is specified, create volume here to avoid errors
67+
if ns.ephemeral {
68+
volID := req.GetVolumeId()
69+
volName := fmt.Sprintf("ephemeral-%s", volID)
70+
vol, err := createHostpathVolume(req.GetVolumeId(), volName, maxStorageCapacity, mountAccess)
71+
if err != nil && !os.IsExist(err) {
72+
glog.Error("ephemeral mode failed to create volume: ", err)
73+
return nil, status.Error(codes.Internal, err.Error())
74+
}
75+
glog.V(4).Infof("ephemeral mode: created volume: %s", vol.VolPath)
76+
}
77+
6378
vol, err := getVolumeByID(req.GetVolumeId())
6479
if err != nil {
6580
return nil, status.Error(codes.NotFound, err.Error())
@@ -150,9 +165,16 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
150165
options = append(options, "ro")
151166
}
152167
mounter := mount.New("")
153-
path := provisionRoot + volumeId
168+
path := getVolumePath(volumeId)
169+
154170
if err := mounter.Mount(path, targetPath, "", options); err != nil {
155-
return nil, err
171+
var errList strings.Builder
172+
errList.WriteString(err.Error())
173+
if ns.ephemeral {
174+
if rmErr := os.RemoveAll(path); rmErr != nil && !os.IsNotExist(rmErr) {
175+
errList.WriteString(fmt.Sprintf(" :%s", rmErr.Error()))
176+
}
177+
}
156178
}
157179
}
158180

@@ -196,6 +218,13 @@ func (ns *nodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpu
196218
glog.V(4).Infof("hostpath: volume %s/%s has been unmounted.", targetPath, volumeID)
197219
}
198220

221+
if ns.ephemeral {
222+
glog.V(4).Infof("deleting volume %s", volumeID)
223+
if err := deleteHostpathVolume(volumeID); err != nil && !os.IsNotExist(err) {
224+
return nil, status.Error(codes.Internal, fmt.Sprintf("failed to delete volume: %s", err))
225+
}
226+
}
227+
199228
return &csi.NodeUnpublishVolumeResponse{}, nil
200229
}
201230

0 commit comments

Comments
 (0)