From e48a72203c25503c08c9dd96c405b06e05555bb6 Mon Sep 17 00:00:00 2001 From: Patrick Ohly Date: Mon, 8 Jul 2019 20:22:20 +0200 Subject: [PATCH 1/2] per-volume ephemeral mode This removes the limitation that the driver can only be deployed for one mode or the other. Instead the driver uses the new csi.storage.k8s.io/ephemeral field (https://github.com/kubernetes/kubernetes/issues/79624) in the volume context to determine how it should behave in NodePublishVolume. Supporting both modes in the same deployment makes it possible to test ephemeral mode without having to change how the Prow jobs deploy the driver, which is once as part of the cluster setup. The --ephemeral parameter is still supported and can be used to force the driver into ephemeral mode, which is useful when deploying on Kubernetes 1.15 where csi.storage.k8s.io/ephemeral is not supported. --- README.md | 5 ++++- cmd/hostpathplugin/main.go | 2 +- pkg/hostpath/controllerserver.go | 2 +- pkg/hostpath/hostpath.go | 4 +++- pkg/hostpath/nodeserver.go | 10 ++++++---- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 281f50934..d1e129614 100644 --- a/README.md +++ b/README.md @@ -346,7 +346,7 @@ Follow the following example to create a volume from a volume snapshot: As of version 1.15 of Kubernetes, the CSI Hostpath driver (starting with version 1.0.1) now includes support for inline ephemeral volume. This means that a volume can be specified directly inside a pod spec without the need to use a persistent volume object. Find out how to enable or create a CSI inline driver [here](https://kubernetes-csi.github.io/docs/ephemeral-local-volumes.html) -To test this feature, redeploy the CSI Hostpath plugin YAML by updating the `hostpath` container to use the inline ephemeral mode by setting the `ephemeral` flag, of the driver binary, to true as shown in the following setup: +To test this feature on Kubernetes 1.15, redeploy the CSI Hostpath plugin YAML by updating the `hostpath` container to use the inline ephemeral mode by setting the `ephemeral` flag, of the driver binary, to true as shown in the following setup: ```yaml kind: DaemonSet @@ -369,6 +369,9 @@ spec: ``` Notice the addition of the `ephemeral=true` flag used in the `args:` block in the previous snippet. +This is an intermediate solution for Kubernetes 1.15. Kubernetes 1.16 will provide [additional +information to the driver](https://github.com/kubernetes/kubernetes/pull/79983) which makes it +possible to use the normal deployment for both inline ephemeral volumes and persistent volumes. Once the driver plugin has been deployed, it can be tested by deploying a simple pod which has an inline volume specified in the spec: diff --git a/cmd/hostpathplugin/main.go b/cmd/hostpathplugin/main.go index 983b35769..b86bed943 100644 --- a/cmd/hostpathplugin/main.go +++ b/cmd/hostpathplugin/main.go @@ -33,7 +33,7 @@ var ( endpoint = flag.String("endpoint", "unix://tmp/csi.sock", "CSI endpoint") driverName = flag.String("drivername", "hostpath.csi.k8s.io", "name of the driver") nodeID = flag.String("nodeid", "", "node id") - ephemeral = flag.Bool("ephemeral", false, "deploy in ephemeral mode") + ephemeral = flag.Bool("ephemeral", false, "publish volumes in ephemeral mode even if kubelet did not ask for it (only needed for Kubernetes 1.15)") showVersion = flag.Bool("version", false, "Show version.") // Set by the build process version = "" diff --git a/pkg/hostpath/controllerserver.go b/pkg/hostpath/controllerserver.go index 5fbe65526..e05e31dee 100644 --- a/pkg/hostpath/controllerserver.go +++ b/pkg/hostpath/controllerserver.go @@ -167,7 +167,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol } } - vol, err := createHostpathVolume(volumeID, req.GetName(), capacity, requestedAccessType) + vol, err := createHostpathVolume(volumeID, req.GetName(), capacity, requestedAccessType, false /* ephemeral */) if err != nil { return nil, status.Error(codes.Internal, fmt.Sprintf("failed to create volume: %s", err)) } diff --git a/pkg/hostpath/hostpath.go b/pkg/hostpath/hostpath.go index 725e00129..ea54a333f 100644 --- a/pkg/hostpath/hostpath.go +++ b/pkg/hostpath/hostpath.go @@ -53,6 +53,7 @@ type hostPathVolume struct { VolSize int64 `json:"volSize"` VolPath string `json:"volPath"` VolAccessType accessType `json:"volAccessType"` + Ephemeral bool `json:"ephemeral"` } type hostPathSnapshot struct { @@ -148,7 +149,7 @@ func getVolumePath(volID string) string { // createVolume create the directory for the hostpath volume. // It returns the volume path or err if one occurs. -func createHostpathVolume(volID, name string, cap int64, volAccessType accessType) (*hostPathVolume, error) { +func createHostpathVolume(volID, name string, cap int64, volAccessType accessType, ephemeral bool) (*hostPathVolume, error) { path := getVolumePath(volID) if volAccessType == mountAccess { err := os.MkdirAll(path, 0777) @@ -163,6 +164,7 @@ func createHostpathVolume(volID, name string, cap int64, volAccessType accessTyp VolSize: cap, VolPath: path, VolAccessType: volAccessType, + Ephemeral: ephemeral, } hostPathVolumes[volID] = hostpathVol return &hostpathVol, nil diff --git a/pkg/hostpath/nodeserver.go b/pkg/hostpath/nodeserver.go index 077692452..2bc59add0 100644 --- a/pkg/hostpath/nodeserver.go +++ b/pkg/hostpath/nodeserver.go @@ -57,6 +57,8 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis } targetPath := req.GetTargetPath() + ephemeralVolume := req.GetVolumeContext()["csi.storage.k8s.io/ephemeral"] == "true" || + req.GetVolumeContext()["csi.storage.k8s.io/ephemeral"] == "" && ns.ephemeral // Kubernetes 1.15 doesn't have csi.storage.k8s.io/ephemeral. if req.GetVolumeCapability().GetBlock() != nil && req.GetVolumeCapability().GetMount() != nil { @@ -64,10 +66,10 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis } // if ephemeral is specified, create volume here to avoid errors - if ns.ephemeral { + if ephemeralVolume { volID := req.GetVolumeId() volName := fmt.Sprintf("ephemeral-%s", volID) - vol, err := createHostpathVolume(req.GetVolumeId(), volName, maxStorageCapacity, mountAccess) + vol, err := createHostpathVolume(req.GetVolumeId(), volName, maxStorageCapacity, mountAccess, ephemeralVolume) if err != nil && !os.IsExist(err) { glog.Error("ephemeral mode failed to create volume: ", err) return nil, status.Error(codes.Internal, err.Error()) @@ -170,7 +172,7 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis if err := mounter.Mount(path, targetPath, "", options); err != nil { var errList strings.Builder errList.WriteString(err.Error()) - if ns.ephemeral { + if vol.Ephemeral { if rmErr := os.RemoveAll(path); rmErr != nil && !os.IsNotExist(rmErr) { errList.WriteString(fmt.Sprintf(" :%s", rmErr.Error())) } @@ -218,7 +220,7 @@ func (ns *nodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpu glog.V(4).Infof("hostpath: volume %s/%s has been unmounted.", targetPath, volumeID) } - if ns.ephemeral { + if vol.Ephemeral { glog.V(4).Infof("deleting volume %s", volumeID) if err := deleteHostpathVolume(volumeID); err != nil && !os.IsNotExist(err) { return nil, status.Error(codes.Internal, fmt.Sprintf("failed to delete volume: %s", err)) From 37803e69af7bb1d9267da5d8e0047166342ebd66 Mon Sep 17 00:00:00 2001 From: Patrick Ohly Date: Mon, 15 Jul 2019 19:04:36 +0200 Subject: [PATCH 2/2] deprecation warning for -ephemeral We want developers to be aware that -ephemeral is going to go away, so always warn about it on stderr. --- cmd/hostpathplugin/main.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd/hostpathplugin/main.go b/cmd/hostpathplugin/main.go index b86bed943..44c253b2c 100644 --- a/cmd/hostpathplugin/main.go +++ b/cmd/hostpathplugin/main.go @@ -48,6 +48,10 @@ func main() { return } + if *ephemeral { + fmt.Fprintln(os.Stderr, "Deprecation warning: The ephemeral flag is deprecated and should only be used when deploying on Kubernetes 1.15. It will be removed in the future.") + } + handle() os.Exit(0) }