Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified charts/latest/csi-driver-smb-v0.0.0.tgz
Binary file not shown.
5 changes: 5 additions & 0 deletions charts/latest/csi-driver-smb/templates/csi-smb-driver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@ metadata:
spec:
attachRequired: false
podInfoOnMount: true
volumeLifecycleModes:
- Persistent
{{- if .Values.feature.enableInlineVolume }}
- Ephemeral
{{- end }}
26 changes: 26 additions & 0 deletions charts/latest/csi-driver-smb/templates/rbac-csi-smb.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,30 @@ roleRef:
kind: ClusterRole
name: {{ .Values.rbac.name }}-external-resizer-role
apiGroup: rbac.authorization.k8s.io
---
{{- if .Values.feature.enableInlineVolume }}
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-{{ .Values.rbac.name }}-node-secret-role
{{ include "smb.labels" . | indent 2 }}
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-{{ .Values.rbac.name }}-node-secret-binding
{{ include "smb.labels" . | indent 2 }}
subjects:
- kind: ServiceAccount
name: {{ .Values.serviceAccount.node }}
namespace: {{ .Release.Namespace }}
roleRef:
kind: ClusterRole
name: csi-{{ .Values.rbac.name }}-node-secret-role
apiGroup: rbac.authorization.k8s.io
{{- end }}
{{ end }}
1 change: 1 addition & 0 deletions charts/latest/csi-driver-smb/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ driver:

feature:
enableGetVolumeStats: true
enableInlineVolume: true

controller:
name: csi-smb-controller
Expand Down
3 changes: 3 additions & 0 deletions deploy/csi-smb-driver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ metadata:
spec:
attachRequired: false
podInfoOnMount: true
volumeLifecycleModes:
- Persistent
- Ephemeral
27 changes: 27 additions & 0 deletions deploy/example/nginx-pod-smb-inline-volume.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
kind: Pod
apiVersion: v1
metadata:
name: nginx-smb-inline-volume
spec:
nodeSelector:
"kubernetes.io/os": linux
containers:
- image: mcr.microsoft.com/mirror/docker/library/nginx:1.23
name: nginx-smb
command:
- "/bin/bash"
- "-c"
- set -euo pipefail; while true; do echo $(date) >> /mnt/smb/outfile; sleep 1; done
volumeMounts:
- name: persistent-storage
mountPath: "/mnt/smb"
readOnly: false
volumes:
- name: persistent-storage
csi:
driver: smb.csi.k8s.io
volumeAttributes:
source: //smb-server.default.svc.cluster.local/share # required
secretName: smbcreds # required, secretNamespace is the same as the pod
mountOptions: "dir_mode=0777,file_mode=0777,cache=strict,actimeo=30,nosharesock" # optional
22 changes: 22 additions & 0 deletions deploy/rbac-csi-smb.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,25 @@ roleRef:
kind: ClusterRole
name: smb-external-resizer-role
apiGroup: rbac.authorization.k8s.io
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-smb-node-secret-role
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-smb-node-secret-binding
subjects:
- kind: ServiceAccount
name: csi-smb-node-sa
namespace: kube-system
roleRef:
kind: ClusterRole
name: csi-smb-node-secret-role
apiGroup: rbac.authorization.k8s.io
48 changes: 42 additions & 6 deletions pkg/smb/nodeserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,14 @@ import (

"golang.org/x/net/context"

volumehelper "github.com/kubernetes-csi/csi-driver-smb/pkg/util"
"github.com/kubernetes-csi/csi-driver-smb/pkg/util"
azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
)

// NodePublishVolume mount the volume from staging to target path
func (d *Driver) NodePublishVolume(_ context.Context, req *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) {
if req.GetVolumeCapability() == nil {
func (d *Driver) NodePublishVolume(ctx context.Context, req *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) {
volCap := req.GetVolumeCapability()
if volCap == nil {
return nil, status.Error(codes.InvalidArgument, "Volume capability missing in request")
}
volumeID := req.GetVolumeId()
Expand All @@ -55,6 +56,20 @@ func (d *Driver) NodePublishVolume(_ context.Context, req *csi.NodePublishVolume
return nil, status.Error(codes.InvalidArgument, "Target path not provided")
}

context := req.GetVolumeContext()
if context != nil && strings.EqualFold(context[ephemeralField], trueValue) {
// ephemeral volume
util.SetKeyValueInMap(context, secretNamespaceField, context[podNamespaceField])
klog.V(2).Infof("NodePublishVolume: ephemeral volume(%s) mount on %s", volumeID, target)
_, err := d.NodeStageVolume(ctx, &csi.NodeStageVolumeRequest{
StagingTargetPath: target,
VolumeContext: context,
VolumeCapability: volCap,
VolumeId: volumeID,
})
return &csi.NodePublishVolumeResponse{}, err
}

source := req.GetStagingTargetPath()
if len(source) == 0 {
return nil, status.Error(codes.InvalidArgument, "Staging target not provided")
Expand Down Expand Up @@ -110,7 +125,7 @@ func (d *Driver) NodeUnpublishVolume(_ context.Context, req *csi.NodeUnpublishVo
}

// NodeStageVolume mount the volume to a staging path
func (d *Driver) NodeStageVolume(_ context.Context, req *csi.NodeStageVolumeRequest) (*csi.NodeStageVolumeResponse, error) {
func (d *Driver) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRequest) (*csi.NodeStageVolumeResponse, error) {
volumeID := req.GetVolumeId()
if len(volumeID) == 0 {
return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request")
Expand All @@ -132,7 +147,8 @@ func (d *Driver) NodeStageVolume(_ context.Context, req *csi.NodeStageVolumeRequ
secrets := req.GetSecrets()
gidPresent := checkGidPresentInMountFlags(mountFlags)

var source, subDir string
var source, subDir, secretName, secretNamespace, ephemeralVolMountOptions string
var ephemeralVol bool
subDirReplaceMap := map[string]string{}
for k, v := range context {
switch strings.ToLower(k) {
Expand All @@ -146,6 +162,14 @@ func (d *Driver) NodeStageVolume(_ context.Context, req *csi.NodeStageVolumeRequ
subDirReplaceMap[pvcNameMetadata] = v
case pvNameKey:
subDirReplaceMap[pvNameMetadata] = v
case secretNameField:
secretName = v
case secretNamespaceField:
secretNamespace = v
case ephemeralField:
ephemeralVol = strings.EqualFold(v, trueValue)
case mountOptionsField:
ephemeralVolMountOptions = v
}
}

Expand All @@ -171,8 +195,20 @@ func (d *Driver) NodeStageVolume(_ context.Context, req *csi.NodeStageVolumeRequ
}
}

if ephemeralVol {
mountFlags = strings.Split(ephemeralVolMountOptions, ",")
}

// in guest login, username and password options are not needed
requireUsernamePwdOption := !hasGuestMountOptions(mountFlags)
if ephemeralVol && requireUsernamePwdOption {
klog.V(2).Infof("NodeStageVolume: getting username and password from secret %s in namespace %s", secretName, secretNamespace)
var err error
username, password, domain, err = d.GetUserNamePasswordFromSecret(ctx, secretName, secretNamespace)
if err != nil {
return nil, status.Error(codes.Internal, fmt.Sprintf("Error getting username and password from secret %s in namespace %s: %v", secretName, secretNamespace, err))
}
}

var mountOptions, sensitiveMountOptions []string
if runtime.GOOS == "windows" {
Expand Down Expand Up @@ -236,7 +272,7 @@ func (d *Driver) NodeStageVolume(_ context.Context, req *csi.NodeStageVolumeRequ
return Mount(d.mounter, source, targetPath, "cifs", mountOptions, sensitiveMountOptions, volumeID)
}
timeoutFunc := func() error { return fmt.Errorf("time out") }
if err := volumehelper.WaitUntilTimeout(90*time.Second, execFunc, timeoutFunc); err != nil {
if err := util.WaitUntilTimeout(90*time.Second, execFunc, timeoutFunc); err != nil {
return nil, status.Error(codes.Internal, fmt.Sprintf("volume(%s) mount %q on %q failed with %v", volumeID, source, targetPath, err))
}
klog.V(2).Infof("volume(%s) mount %q on %q succeeded", volumeID, source, targetPath)
Expand Down
31 changes: 31 additions & 0 deletions pkg/smb/nodeserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,37 @@ func TestNodePublishVolume(t *testing.T) {
Readonly: true},
expectedErr: testutil.TestError{},
},
{
desc: "[Error] failed to create ephemeral Volume",
req: &csi.NodePublishVolumeRequest{VolumeCapability: &csi.VolumeCapability{AccessMode: &volumeCap},
VolumeId: "vol_1",
TargetPath: targetTest,
StagingTargetPath: sourceTest,
Readonly: true,
VolumeContext: map[string]string{ephemeralField: "true"},
},
expectedErr: testutil.TestError{
DefaultError: status.Error(codes.InvalidArgument, "source field is missing, current context: map[csi.storage.k8s.io/ephemeral:true secretnamespace:]"),
},
},
{
desc: "[error] failed request with ephemeral Volume",
req: &csi.NodePublishVolumeRequest{VolumeCapability: &csi.VolumeCapability{AccessMode: &volumeCap},
VolumeId: "vol_1",
TargetPath: targetTest,
StagingTargetPath: sourceTest,
Readonly: true,
VolumeContext: map[string]string{
ephemeralField: "true",
sourceField: "source",
podNamespaceField: "podnamespace",
},
},
skipOnWindows: true,
expectedErr: testutil.TestError{
DefaultError: status.Error(codes.Internal, "Error getting username and password from secret in namespace podnamespace: could not username and password from secret(): KubeClient is nil"),
},
},
}

// Setup
Expand Down
Loading
Loading