From 34d0e6d84d8032a160d5bb6977845c00f8cb5274 Mon Sep 17 00:00:00 2001 From: andyzhangx Date: Sun, 19 Jun 2022 10:23:57 +0000 Subject: [PATCH] feat: support pv/pvc metadata in subDir parameter fix fix --- charts/latest/csi-driver-nfs-v4.1.0.tgz | Bin 3687 -> 3705 bytes .../templates/csi-nfs-controller.yaml | 1 + deploy/csi-nfs-controller.yaml | 1 + docs/driver-parameters.md | 6 ++ pkg/nfs/controllerserver.go | 28 +++--- pkg/nfs/controllerserver_test.go | 84 ++++++++++++++++++ pkg/nfs/nfs.go | 18 ++++ pkg/nfs/nfs_test.go | 52 +++++++++++ pkg/nfs/nodeserver.go | 11 +++ pkg/nfs/nodeserver_test.go | 17 ++++ test/e2e/e2e_suite_test.go | 2 +- 11 files changed, 208 insertions(+), 12 deletions(-) diff --git a/charts/latest/csi-driver-nfs-v4.1.0.tgz b/charts/latest/csi-driver-nfs-v4.1.0.tgz index 6ee357fa9c8950e9d988b1450c8dc7454147970d..b20cd3d2c39ddcac1c06f5a67cb95056b0d17dd5 100644 GIT binary patch delta 3643 zcmV-B4#e^29QhoOK>^Q^LL`3&0A;I=@85n004b3a_3-XZ9M3Q6e~l!^)-!ldhwG@X5AM5EGPj4FSUG}ZRmLH`&| zKJ?+xstgQ;gkQ4(N{$+p$4P=AR8`8G%*gKq-Js(=_l#dkxzy}`LRg0CfgQja``_*D zb?f%ud)Ixj|EDNXrnE?YBLieAgzFoRCS-)62LQl_%6%|JVk#8XLQX>%MKYkGeesj> zl_n#~N4}yXUuhx92-|;rs8W`VD4%uKWE4U~IFZxYvovGuR4^J%LpUCu2z@G1A=kD+ zr0A&>6KXsM%4RMkj;PXd8eIIO3_E2Oj9RC20#!yP+tv|n#0aAkWv`zR6_*M^@+BGDLv zmKnkp{Bw-letrviTOh8nf=kL63^4B!+nr=8vH<$1K?@iXrV!}RJcLWa?ZZr=`7S|R z^1zHIxR!!3ly2AIL*>t(`HH|6oR9=T456QMkh5#Zm4+A65RW}i4oFm=iU;6!HnW|1 zPI_VaVGt>rOWc10NDTc`lnGTv`&0;>ckkYL-Vlk-q*Ws1WWex4{}(B;w2*E-l&d@D zjB@-USZ2ns((t^CY=8{)A(bJtCq%Xx9kla@o>!8_jJZXrcvfK;jfe`tEVIn`C;pKr zZKUW1${!xMPN$4;oL4ni#25+F<5MAZ2)+N=+wGZVV)TC-PLPGL>j7K}c|rN;qY;f| zztz@B+VTKmt_lGh;*exa18f1A5Xy`k!0kx0%C~U9GQ;Z!DwX~x)#HB%rBAR{;Q^50 zkaDW0)~h)a>LbHQ3z20XB zj;^TEs;Ga!;SeJoLhD5IqcO%A!`4Rh^HoZXz#n}S|6apLR3eiR=8|jn*Ni4qm-dhZ z6YHgRI-QTyE4tlzsBJZsdfG)^zQKP!qh4*_N3XWF;0%W-kw<8DJHgRx zbBT}$3L}YH<(r_{`QXxQ)@HM(d;~TKREC7aVF+WbQx&$`RX-AoNVPRl7s|MlAsuBB z{ZzzuvmunDY#VyMCFZA+PKd@L>X^2@tt}U9o@R{o9YZ1f@u#;1er^n{ysM$&SZ=)> zA0L0V)XskzlhmI3+b5qsAN2!$rSCt+I{at5w^KX+?e1=OUe13{QQ-3!>!=P@FhZ@3 zBZx6&Vv4cx6gKjX+%^(;-e&>P7^91N?^MJJlqNb;Zy{w!6q;}{^gICLKqAe+_l<$8 zltj3HeGS1G+IGQ7@f2=u3=fW&@2h-A*>8VI*K(m3+}yOl_b-W##?LL&Z>cP`|MM}j z6r~DudS57Ljs16f+jabRZ>RTS|4&k`uiI~6LX!{_Y8X<6dYa;XV#E@SF@!hmn;Xxw z&5o{8!eh{5wEMF;Rh!R|%^BEs*VjJ8IHVk*WzNN>SquDmjg4Rfmu0YK8+>tyqiKKn zX@XMH7~!iq3-bu}w(Uon^t0iRUO~&B6GI-`&yF=_0W6CmjFBbtSP~lfa?Kqv_t}J1 zBu#5aCCZg1JTjq3lf!B3lMqfu82f{1tyh6SEbExZJlEGySYcU+!P0&+fZdMfWcz-G zbZ6$o#D>4kyuB$TP1nz(u!)??Ob#3HzUL_1 zVlaSWs;1ODZT+}Br@nBIZt%hjy=QFxG$&MY#_qw`0Z5lZUgW?&Y?Xj_AWRA1h_OWz zEcOk2XumiN9b#H!7)oeXvmAeB4d&xlvkWJ7&8t?IXcgPZCDr4mp$gn;KGF=yD$A}W zqy_O*@UGcXS2t*(LSU3c$w3K^oYQ}dH{6mq zmZ;SJ53k=J9-bZb`#&}`WJqF^zFk8q`1%$b9QGTC;FXrdcRs`~yzaj7K;_2BC-n(B z;pY>m)PcjxLom^e`4@jE5na^R<+POXTqp8*cC_s20VXzaXVYB^3*hpDM2{UGH4Yv3 zhA-6q+;sw!0di|=^&q>v3+4@L?7~;zxi)uuWrho(6_~qU%~!8b*a}L&PG75yH&fTD zVlG=a*V1zBYnq_Q^!~P5Xy6hUek!EiZ{C5bEY1@i)#Y{6Ci{QATj@@f_FYtGg>sm( zT(j<=Iu&l$Y7QT&P1ME2No$nEG+9&)g;8dGzu+3LbX72^q!Y?;gz+qkJ}(hT$$&Dd zDc0l(K;k%rKU)2N_0QiQemp*D{aI;17!#ML1@R*l5k}lSxY{V|*WS!(*@`!NX@9az zMe{UWv)eTLD~*5me|UZJ>G0_M_^`=?Bac%-x!(Wb^+Esm{OIKH^waUl=ccCaY-rZF z%#C|mgslzTtS0*D{1QY%@A^H7W=i?Zft+GYvE!`$^DK%{qAEZd?3Ii~t z$l@~`F4p9A&i+gkZ(|*^%QcQ%mVEOrm2r9%w%f~mp7DQT3wkq)M_iWneon5~ja-Yr zYIUg;T10|{@cH1hRJY{Hlob%6ER*2p zq)5pq_eFoLpJ_~`3$+NVo6u868|K{Cyiqt=HN?nEMP$yMmThlQ6E>HZo~9VWp%srP zT|Qj7m12_WslBCi{kMl9*W!P!lJcQ=B>b<_+3j@d_}|Xn%l-c+DZcMl;J*B_XmNjZ z(#_GqgZ{D0@2&;{tAW7`wj)}TXncnM$*43zT5*4u(7A=*=n$i6#PFktadt=O)Uc$q zy8>IoF!HOE!Qx%X+~fFgl#Ve$Ntjo~L{?I&+{m=ehpKW%^8;mAA^6iDkXzJNWV%cPl)H`ez*&T{hw~L##Eh+&pCwPw%*vgh^JY>{hJk;lh@utp zcZnt1nco>jT={y^DqL~#{`Oj&v7yVN01*1h*V%urD~y!esY#*)-g!zyAL7(YeJNPu_n#dNRau18lm%5}tq5 zqs%*3mU%Uaa?`tdr-qr|GSl%5I^F5skvRTOOh*I#`vM_#_YPMVJ3S`H}m~`@DF`Z=%@SAsX5mdu#jXni0lwV5egFmF{Ln;;KX7+#bzr)+wTqoMvTy8<568gqG_yZ3bkqEyhX%_QX9^5 z!#UvuxxRzs^4YwFR=RAs_0x(JHP-Q<6S^0{NC+8IUbcXyF|6G_j?fxc-=$KT#{1Ko z=i^Go{WIk;<)g>2@!B1Ae~^C!iz`#-(Ch2Q_%etG}zNy-+S5^c=DzOm(2-u)KL zAfwE<0!T@8K}M(oZwo$;sREUy79j#PM#f;o#K0xTDIdKBiHvAEL3@8zEIlVY_O^hd zJLkjeRN|0cVeGP#|Mg=4pE#S^pQ%Y5OOT=jMmYvvaM(ZZYa!9wf&-Bxg2R`CKEzZi zFBnnXw*Nc!y2n3%(FZMW*2R@JKItK`MoDdR{_cPLL`3$K-sG6`?uc#KuRP)bdcHoR82x18RoP(TQL#{NvkcN2dd2&Fa`cgaq7uifW^PKd; z^1~ofG?%yskQjgZ=O`1ZjP|JzI&a^;^}Hbxok^=i$jN}=`~J^TWN9JYd@A?ulrzfl zvtXH-!%D;RuCf6#)W=kY(4G+4W^~ZbA9`L%8Z+h=rQ%tIVKgEt1hdUD;~)74qO_5s zn<#&H;m>!=CsYB@f&%u7rbQ7arae{v=gnbX-TF5KPM<0x6Ec>mt zPSTbK5OY-s;24J_V;W!w$b?X4b)}3;8PZWE(N9He zgAJh^W!up6EipfpbV4*1S;w^P?d-T@^E_j$?-&Z<_dmQH@N;8m$8u|Xe0jeh(b>+ql5-d^qex4*yJ*`EJiqQR#z)=?d*V1!y5M-XGm z#1v!WDQxB)xiAuV-X{Uk7^AED=v2fClqNb;Zy;qz6q z;W6kj+W2fv)#h_#YX-L8?X3?n4k<@ynRBt})&hV2#%8dAt1?)#4L&=>(e(T{K`DP} zjPSQP3-bsLcI`)+^t0iR-ayNr6GI-`&yF=_0W6CmjFBbtToM}ja@`#<_t~UXBu#5a zCCZg1JTj?Blf!8olMqfu82f{1ZB&6kEE|~TJh!({SYcU+!P0RvfZfjKWczN0FSi^$P~s{*V2f48%HP|N>%o&E0a*8jgm^L^jDqC5`a z*rs|3a_yCif+S5@qry15&0_OY@ zmfKW>%*{2=!phbeRB`lRUfP4ZyKr4^O-6Z!Hgh?0RN~9=*77HZz1G4*-*8LfSfWyg z-@kfye0*`z@Bh%yks*mu`gRYg;Ol#AaM&*sK|ZPT?BtpARCxyu0uR9?EaqRJM08ab z^?9j?xlW4nf@j%z15AHxEzVZ37G&y5engKQA2kjg_l7Uj{@fb^lre8>KJ~o09N6-X zHFn`|;JJc!du4_Tp%pN?UoAne(7_7uzD@s1?Q5E#$n@c^TIk?v z5`HSAK5PyuRTk$pjOz9}YLmm>y>zEa`yr~cLOD!Zu2~OIoeF=qYc+=t)h6moLmu&T#vtM?^1s$w1@-?;nUH1>D`iBP*y;M zvP|Nqu|zc%EOy1?c^hk;{*1aV+tj(VC2ZJ*HoY?mIwkBF8JYGm5~<=B@?bH0 z-L1Y(QBn~%4_@!6QxU7V;x2dArCple+JU>fwjt0sOp26@a$nT?iN;jA?1`|t3B6>t zVUBXmfx>^usv+%NDk5`~v}}8eny|UN^fbi~j;(k^=|17gP>M;ar}pB}?G{-qx3&16 zdrA3FJQM!c>Fjqpb^LGdV0-`nMVjyX6}T_IELz+jopf__@Th<4>bt9fz-ksTgYAgc zBpP4fpBa@Vqbu$bIv?^Y9bz<%7=92j&h7}E8>l^dD1`%qQxXuhWmD+Isv{yny>wSSZFJo5VhYw-VWZ?}H`<85!hx3&M5 zXeIogU?O-Q9{~Sb9eG~hKTBhxv9Bf3IGQ>iVUiWfN59!uMN(0}*jQ(?`o2hKTvBmS zCis7l`aw+)&s907P4gAh40b?BI-;B~TO5c4=PtX2Ymu=S1_%Qwu8>>QR%E(N1C+as z^u$$!vWN2(S;UO3n7>G!pqZ5iLFdh+UJL{OM&U;*PhKd?2>6zt-5Qntfjbe2f^DB7{u?oAJ8ku!Q}B z<19^fzb;#boAsC9emc3d;N;o64<|1MPi_EYH(0`pdX)L#$~LbiQSSOs@6@pJdzODi zzJemglNN1^jl;UihKqjRMonW|hPYp{vn@cZDnLB0>iEpg`AgS6?&sR?U$|%#&clip zP1(V!D#k~7WG~D8|0$+CX5E*?m;5%G3zo(HFO7|T3vDU>D+eUo=2<^BBOc*gjlZ|I}1&OA)swLE>ne!eIBT8+!&JEXu6Xf~DDhR zQq)+-lP>5{1S272OnKP?n&z-}`#eHx+ZQHheOYQ#x00960!Kr%N09*h7k3c>4 diff --git a/charts/latest/csi-driver-nfs/templates/csi-nfs-controller.yaml b/charts/latest/csi-driver-nfs/templates/csi-nfs-controller.yaml index a734ff4e..5cba9758 100644 --- a/charts/latest/csi-driver-nfs/templates/csi-nfs-controller.yaml +++ b/charts/latest/csi-driver-nfs/templates/csi-nfs-controller.yaml @@ -50,6 +50,7 @@ spec: - "--csi-address=$(ADDRESS)" - "--leader-election" - "--leader-election-namespace={{ .Release.Namespace }}" + - "--extra-create-metadata=true" env: - name: ADDRESS value: /csi/csi.sock diff --git a/deploy/csi-nfs-controller.yaml b/deploy/csi-nfs-controller.yaml index 28a0165c..3db5d834 100644 --- a/deploy/csi-nfs-controller.yaml +++ b/deploy/csi-nfs-controller.yaml @@ -38,6 +38,7 @@ spec: - "--csi-address=$(ADDRESS)" - "--leader-election" - "--leader-election-namespace=kube-system" + - "--extra-create-metadata=true" env: - name: ADDRESS value: /csi/csi.sock diff --git a/docs/driver-parameters.md b/docs/driver-parameters.md index bb702878..f2db0354 100644 --- a/docs/driver-parameters.md +++ b/docs/driver-parameters.md @@ -21,6 +21,12 @@ volumeAttributes.share | NFS share path | `/` | Yes | volumeAttributes.mountPermissions | mounted folder permissions. The default is `0777` | | No | ### Tips +#### `subDir` parameter supports following pv/pvc metadata transform +> if `subDir` value contains following strings, it would transforms into corresponding pv/pvc name or namespace + - `${pvc.metadata.name}` + - `${pvc.metadata.namespace}` + - `${pv.metadata.name}` + #### provide `mountOptions` for `DeleteVolume` > since `DeleteVolumeRequest` does not provide `mountOptions`, following is the workaround to provide `mountOptions` for `DeleteVolume`, check details [here](https://github.com/kubernetes-csi/csi-driver-nfs/issues/260) - create a secret with `mountOptions` diff --git a/pkg/nfs/controllerserver.go b/pkg/nfs/controllerserver.go index c1147dfe..9015e7fb 100644 --- a/pkg/nfs/controllerserver.go +++ b/pkg/nfs/controllerserver.go @@ -93,10 +93,11 @@ func (cs *ControllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol for k, v := range parameters { switch strings.ToLower(k) { case paramServer: - // no op case paramShare: - // no op case paramSubDir: + case pvcNamespaceKey: + case pvcNameKey: + case pvNameKey: // no op case mountPermissionsField: if v != "" { @@ -110,7 +111,7 @@ func (cs *ControllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol } } - nfsVol, err := cs.newNFSVolume(name, reqCapacity, parameters) + nfsVol, err := newNFSVolume(name, reqCapacity, parameters) if err != nil { return nil, status.Error(codes.InvalidArgument, err.Error()) } @@ -304,9 +305,10 @@ func (cs *ControllerServer) internalUnmount(ctx context.Context, vol *nfsVolume) return err } -// Convert VolumeCreate parameters to an nfsVolume -func (cs *ControllerServer) newNFSVolume(name string, size int64, params map[string]string) (*nfsVolume, error) { +// newNFSVolume Convert VolumeCreate parameters to an nfsVolume +func newNFSVolume(name string, size int64, params map[string]string) (*nfsVolume, error) { var server, baseDir, subDir string + subDirReplaceMap := map[string]string{} // validate parameters (case-insensitive) for k, v := range params { @@ -317,15 +319,18 @@ func (cs *ControllerServer) newNFSVolume(name string, size int64, params map[str baseDir = v case paramSubDir: subDir = v + case pvcNamespaceKey: + subDirReplaceMap[pvcNamespaceMetadata] = v + case pvcNameKey: + subDirReplaceMap[pvcNameMetadata] = v + case pvNameKey: + subDirReplaceMap[pvNameMetadata] = v } } if server == "" { return nil, fmt.Errorf("%v is a required parameter", paramServer) } - if baseDir == "" { - return nil, fmt.Errorf("%v is a required parameter", paramShare) - } vol := &nfsVolume{ server: server, @@ -336,11 +341,12 @@ func (cs *ControllerServer) newNFSVolume(name string, size int64, params map[str // use pv name by default if not specified vol.subDir = name } else { - vol.subDir = subDir + // replace pv/pvc name namespace metadata in subDir + vol.subDir = replaceWithMap(subDir, subDirReplaceMap) // make volume id unique if subDir is provided vol.uuid = name } - vol.id = cs.getVolumeIDFromNfsVol(vol) + vol.id = getVolumeIDFromNfsVol(vol) return vol, nil } @@ -368,7 +374,7 @@ func getInternalVolumePath(workingMountDir string, vol *nfsVolume) string { } // Given a nfsVolume, return a CSI volume id -func (cs *ControllerServer) getVolumeIDFromNfsVol(vol *nfsVolume) string { +func getVolumeIDFromNfsVol(vol *nfsVolume) string { idElements := make([]string, totalIDElements) idElements[idServer] = strings.Trim(vol.server, "/") idElements[idBaseDir] = strings.Trim(vol.baseDir, "/") diff --git a/pkg/nfs/controllerserver_test.go b/pkg/nfs/controllerserver_test.go index 4b0a52f4..9f3c8c87 100644 --- a/pkg/nfs/controllerserver_test.go +++ b/pkg/nfs/controllerserver_test.go @@ -529,3 +529,87 @@ func TestGetInternalMountPath(t *testing.T) { assert.Equal(t, path, test.result) } } + +func TestNewNFSVolume(t *testing.T) { + cases := []struct { + desc string + name string + size int64 + params map[string]string + expectVol *nfsVolume + expectErr error + }{ + { + desc: "subDir is specified", + name: "pv-name", + size: 100, + params: map[string]string{ + paramServer: "//nfs-server.default.svc.cluster.local", + paramShare: "share", + paramSubDir: "subdir", + }, + expectVol: &nfsVolume{ + id: "nfs-server.default.svc.cluster.local#share#subdir#pv-name", + server: "//nfs-server.default.svc.cluster.local", + baseDir: "share", + subDir: "subdir", + size: 100, + uuid: "pv-name", + }, + }, + { + desc: "subDir with pv/pvc metadata is specified", + name: "pv-name", + size: 100, + params: map[string]string{ + paramServer: "//nfs-server.default.svc.cluster.local", + paramShare: "share", + paramSubDir: fmt.Sprintf("subdir-%s-%s-%s", pvcNameMetadata, pvcNamespaceMetadata, pvNameMetadata), + pvcNameKey: "pvcname", + pvcNamespaceKey: "pvcnamespace", + pvNameKey: "pvname", + }, + expectVol: &nfsVolume{ + id: "nfs-server.default.svc.cluster.local#share#subdir-pvcname-pvcnamespace-pvname#pv-name", + server: "//nfs-server.default.svc.cluster.local", + baseDir: "share", + subDir: "subdir-pvcname-pvcnamespace-pvname", + size: 100, + uuid: "pv-name", + }, + }, + { + desc: "subDir not specified", + name: "pv-name", + size: 200, + params: map[string]string{ + paramServer: "//nfs-server.default.svc.cluster.local", + paramShare: "share", + }, + expectVol: &nfsVolume{ + id: "nfs-server.default.svc.cluster.local#share#pv-name#", + server: "//nfs-server.default.svc.cluster.local", + baseDir: "share", + subDir: "pv-name", + size: 200, + uuid: "", + }, + }, + { + desc: "server value is empty", + params: map[string]string{}, + expectVol: nil, + expectErr: fmt.Errorf("%s is a required parameter", paramServer), + }, + } + + for _, test := range cases { + vol, err := newNFSVolume(test.name, test.size, test.params) + if !reflect.DeepEqual(err, test.expectErr) { + t.Errorf("[test: %s] Unexpected error: %v, expected error: %v", test.desc, err, test.expectErr) + } + if !reflect.DeepEqual(vol, test.expectVol) { + t.Errorf("[test: %s] Unexpected vol: %v, expected vol: %v", test.desc, vol, test.expectVol) + } + } +} diff --git a/pkg/nfs/nfs.go b/pkg/nfs/nfs.go index b45d707e..1ccd04c6 100644 --- a/pkg/nfs/nfs.go +++ b/pkg/nfs/nfs.go @@ -17,6 +17,8 @@ limitations under the License. package nfs import ( + "strings" + "github.com/container-storage-interface/spec/lib/go/csi" "k8s.io/klog/v2" mount "k8s.io/mount-utils" @@ -58,6 +60,12 @@ const ( paramSubDir = "subdir" mountOptionsField = "mountoptions" mountPermissionsField = "mountpermissions" + pvcNameKey = "csi.storage.k8s.io/pvc/name" + pvcNamespaceKey = "csi.storage.k8s.io/pvc/namespace" + pvNameKey = "csi.storage.k8s.io/pv/name" + pvcNameMetadata = "${pvc.metadata.name}" + pvcNamespaceMetadata = "${pvc.metadata.namespace}" + pvNameMetadata = "${pv.metadata.name}" ) func NewDriver(options *DriverOptions) *Driver { @@ -132,3 +140,13 @@ func IsCorruptedDir(dir string) bool { _, pathErr := mount.PathExists(dir) return pathErr != nil && mount.IsCorruptedMnt(pathErr) } + +// replaceWithMap replace key with value for str +func replaceWithMap(str string, m map[string]string) string { + for k, v := range m { + if k != "" { + str = strings.ReplaceAll(str, k, v) + } + } + return str +} diff --git a/pkg/nfs/nfs_test.go b/pkg/nfs/nfs_test.go index e1035832..c4e23f89 100644 --- a/pkg/nfs/nfs_test.go +++ b/pkg/nfs/nfs_test.go @@ -178,3 +178,55 @@ func TestNewNodeServiceCapability(t *testing.T) { assert.Equal(t, resp.XXX_sizecache, int32(0)) } } + +func TestReplaceWithMap(t *testing.T) { + tests := []struct { + desc string + str string + m map[string]string + expected string + }{ + { + desc: "empty string", + str: "", + expected: "", + }, + { + desc: "empty map", + str: "", + m: map[string]string{}, + expected: "", + }, + { + desc: "empty key", + str: "prefix-" + pvNameMetadata, + m: map[string]string{"": "pv"}, + expected: "prefix-" + pvNameMetadata, + }, + { + desc: "empty value", + str: "prefix-" + pvNameMetadata, + m: map[string]string{pvNameMetadata: ""}, + expected: "prefix-", + }, + { + desc: "one replacement", + str: "prefix-" + pvNameMetadata, + m: map[string]string{pvNameMetadata: "pv"}, + expected: "prefix-pv", + }, + { + desc: "multiple replacements", + str: pvcNamespaceMetadata + pvcNameMetadata, + m: map[string]string{pvcNamespaceMetadata: "namespace", pvcNameMetadata: "pvcname"}, + expected: "namespacepvcname", + }, + } + + for _, test := range tests { + result := replaceWithMap(test.str, test.m) + if result != test.expected { + t.Errorf("test[%s]: unexpected output: %v, expected result: %v", test.desc, result, test.expected) + } + } +} diff --git a/pkg/nfs/nodeserver.go b/pkg/nfs/nodeserver.go index 0688c78a..e7aae1c7 100644 --- a/pkg/nfs/nodeserver.go +++ b/pkg/nfs/nodeserver.go @@ -57,6 +57,8 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis } var server, baseDir, subDir string + subDirReplaceMap := map[string]string{} + mountPermissions := ns.Driver.mountPermissions performChmodOp := (mountPermissions > 0) for k, v := range req.GetVolumeContext() { @@ -67,6 +69,12 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis baseDir = v case paramSubDir: subDir = v + case pvcNamespaceKey: + subDirReplaceMap[pvcNamespaceMetadata] = v + case pvcNameKey: + subDirReplaceMap[pvcNameMetadata] = v + case pvNameKey: + subDirReplaceMap[pvNameMetadata] = v case mountOptionsField: if v != "" { mountOptions = append(mountOptions, v) @@ -96,6 +104,9 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis server = getServerFromSource(server) source := fmt.Sprintf("%s:%s", server, baseDir) if subDir != "" { + // replace pv/pvc name namespace metadata in subDir + subDir = replaceWithMap(subDir, subDirReplaceMap) + source = strings.TrimRight(source, "/") source = fmt.Sprintf("%s/%s", source, subDir) } diff --git a/pkg/nfs/nodeserver_test.go b/pkg/nfs/nodeserver_test.go index bc21caee..b4e62cb7 100644 --- a/pkg/nfs/nodeserver_test.go +++ b/pkg/nfs/nodeserver_test.go @@ -47,6 +47,13 @@ func TestNodePublishVolume(t *testing.T) { "share": "share", mountPermissionsField: "0755", } + paramsWithMetadata := map[string]string{ + "server": "server", + "share": "share", + pvcNameKey: "pvcname", + pvcNamespaceKey: "pvcnamespace", + pvNameKey: "pvname", + } paramsWithZeroPermissions := map[string]string{ "server": "server", "share": "share", @@ -126,6 +133,16 @@ func TestNodePublishVolume(t *testing.T) { Readonly: true}, expectedErr: nil, }, + { + desc: "[Success] Valid request with pv/pvc metadata", + req: csi.NodePublishVolumeRequest{ + VolumeContext: paramsWithMetadata, + VolumeCapability: &csi.VolumeCapability{AccessMode: &volumeCap}, + VolumeId: "vol_1", + TargetPath: targetTest, + Readonly: true}, + expectedErr: nil, + }, { desc: "[Success] Valid request with 0 mountPermissions", req: csi.NodePublishVolumeRequest{ diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go index 9c225f30..e0d402a4 100644 --- a/test/e2e/e2e_suite_test.go +++ b/test/e2e/e2e_suite_test.go @@ -62,7 +62,7 @@ var ( subDirStorageClassParameters = map[string]string{ "server": nfsServerAddress, "share": nfsShare, - "subDir": "subDirectory", + "subDir": "subDirectory-${pvc.metadata.namespace}", "csi.storage.k8s.io/provisioner-secret-name": "mount-options", "csi.storage.k8s.io/provisioner-secret-namespace": "default", "mountPermissions": "0755",