From 30c0a7b03fc81a31613fc2e8f0faf305be3671d0 Mon Sep 17 00:00:00 2001 From: Thilo Fromm Date: Thu, 16 Oct 2025 09:51:14 +0200 Subject: [PATCH 1/3] feat: Add support for Flatcar Container Linux This change adds support for Flatcar to the blobfuse installer. Changes are minimal; we're re-using the rhcos installer script and the gardenlinux paths. As Flatcar currently does not ship libfuse, we install it alongside blobfuse2. Signed-off-by: Thilo Fromm --- .../templates/csi-blob-node.yaml | 4 +-- pkg/blobfuse-proxy/init.sh | 2 +- pkg/blobfuse-proxy/install-proxy-rhcos.sh | 33 ++++++++++++------- pkg/blobfuse-proxy/server/server.go | 5 +++ 4 files changed, 29 insertions(+), 15 deletions(-) diff --git a/charts/latest/blob-csi-driver/templates/csi-blob-node.yaml b/charts/latest/blob-csi-driver/templates/csi-blob-node.yaml index 7cdd28211..7d4f7680a 100644 --- a/charts/latest/blob-csi-driver/templates/csi-blob-node.yaml +++ b/charts/latest/blob-csi-driver/templates/csi-blob-node.yaml @@ -111,7 +111,7 @@ spec: - name: host-home-kubernetes-bin mountPath: /host/home/kubernetes/bin {{- end }} -{{- if eq .Values.linux.distro "gardenlinux" }} +{{- if or (eq .Values.linux.distro "gardenlinux") (eq .Values.linux.distro "flatcar") }} - name: host-var-bin mountPath: /host/var/bin {{- end }} @@ -300,7 +300,7 @@ spec: hostPath: path: /home/kubernetes/bin {{- end }} -{{- if eq .Values.linux.distro "gardenlinux" }} +{{- if or (eq .Values.linux.distro "gardenlinux") (eq .Values.linux.distro "flatcar") }} - name: host-var-bin hostPath: path: /var/bin diff --git a/pkg/blobfuse-proxy/init.sh b/pkg/blobfuse-proxy/init.sh index af4487c02..1e714fbe2 100755 --- a/pkg/blobfuse-proxy/init.sh +++ b/pkg/blobfuse-proxy/init.sh @@ -39,7 +39,7 @@ echo "Linux distribution: $DISTRIBUTION, Arch: $ARCH" # install blobfuse-proxy and blobfuse/blobfuse2 if needed case "${DISTRIBUTION}" in - "rhcos" | "rhel" | "cos" | "gardenlinux") + "rhcos" | "rhel" | "cos" | "gardenlinux" | "flatcar") . ./blobfuse-proxy/install-proxy-rhcos.sh ;; *) diff --git a/pkg/blobfuse-proxy/install-proxy-rhcos.sh b/pkg/blobfuse-proxy/install-proxy-rhcos.sh index 420542f5a..73a241f92 100644 --- a/pkg/blobfuse-proxy/install-proxy-rhcos.sh +++ b/pkg/blobfuse-proxy/install-proxy-rhcos.sh @@ -16,19 +16,19 @@ set -xe -BIN_PATH=${BIN_PATH:-/usr/local/bin} -if [ "${DISTRIBUTION}" = "cos" ]; then - echo "set BIN_PATH to /home/kubernetes/bin" - BIN_PATH="/home/kubernetes/bin" -fi -if [ "${DISTRIBUTION}" = "gardenlinux" ]; then - echo "set BIN_PATH to /var/bin" - BIN_PATH="/var/bin" -fi -if [ "${CUSTOM_BIN_PATH}" != "" ]; then - echo "set BIN_PATH to ${CUSTOM_BIN_PATH}" - BIN_PATH="${CUSTOM_BIN_PATH}" +if [ -z "${CUSTOM_BIN_PATH:-}" ] ; then + case "${DISTRIBUTION}" in + "cos") + BIN_PATH="/home/kubernetes/bin" ;; + "gardenlinux" | "flatcar") + BIN_PATH="/var/bin" ;; + *) + BIN_PATH=${BIN_PATH:-/usr/local/bin} ;; + esac +else + BIN_PATH="/${CUSTOM_BIN_PATH#/}" fi +echo "set BIN_PATH to ${BIN_PATH}" #copy blobfuse2 binary to BIN_PATH/blobfuse2 updateBlobfuse2="true" @@ -60,6 +60,15 @@ if [ "$updateBlobfuse2" = "true" ];then cp /usr/lib64/libfuse3.so.3* /host/usr/lib64/ fi chmod 755 /host${BIN_PATH}/blobfuse2 + if [ "$DISTRIBUTION" = "flatcar" ] ; then + find /usr/ -name 'libfuse.so.*' -exec cp '{}' /host${BIN_PATH} \; + mv /host${BIN_PATH}/blobfuse2 /host${BIN_PATH}/blobfuse2.bin + { + echo '#!/usr/bin/bash' + echo "LD_LIBRARY_PATH='${BIN_PATH}' exec ${BIN_PATH}/blobfuse2.bin \"\${@}\"" + } >/host${BIN_PATH}/blobfuse2 + chmod 755 /host${BIN_PATH}/blobfuse2 + fi fi if [ "${INSTALL_BLOBFUSE_PROXY}" = "true" ];then diff --git a/pkg/blobfuse-proxy/server/server.go b/pkg/blobfuse-proxy/server/server.go index 9730c83dd..ab7c4bf96 100644 --- a/pkg/blobfuse-proxy/server/server.go +++ b/pkg/blobfuse-proxy/server/server.go @@ -150,6 +150,11 @@ func getBlobfuseVersion() BlobfuseVersion { return BlobfuseV2 } + if strings.EqualFold(osinfo.Distro, "flatcar") { + klog.V(2).Info("proxy default using blobfuse V2 for mounting on Flatcar Container Linux") + return BlobfuseV2 + } + klog.V(2).Info("proxy default using blobfuse V1 for mounting") return BlobfuseV1 } From 69f4b9e2b1eebfbd74da07c5749c17c762b25f4b Mon Sep 17 00:00:00 2001 From: Thilo Fromm Date: Fri, 17 Oct 2025 16:40:55 +0200 Subject: [PATCH 2/3] fix: correctly modify PATH in install-proxy-rhcos.sh The installer script wants to update the PATH variable to include $BIN_PATH in blobfuse-proxs's systemd unit by setting: Environment="PATH=:$PATH" BIN_PATH is evaluated in the installer script, and $PATH is escaped, to be evaluated when the service unit runs. However, environment variables like "$PATH" are NOT evaluated by systemd in Environment="...". Quoting the documentation: " Variable expansion is not performed inside the strings and the "$" character has no special meaning. " https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#Environment This effectively removes all other paths and sets PATH to ONLY . The resulting environment variable PATH contains the actual contents of BIN_PATH and a literal '$PATH'. This commit fixes that by wrapping ExecStart in bash -c '...' and updating PATH there. --- pkg/blobfuse-proxy/install-proxy-rhcos.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/blobfuse-proxy/install-proxy-rhcos.sh b/pkg/blobfuse-proxy/install-proxy-rhcos.sh index 73a241f92..9a9ac238a 100644 --- a/pkg/blobfuse-proxy/install-proxy-rhcos.sh +++ b/pkg/blobfuse-proxy/install-proxy-rhcos.sh @@ -93,8 +93,9 @@ if [ "${INSTALL_BLOBFUSE_PROXY}" = "true" ];then echo "change from /usr/bin/blobfuse-proxy to ${BIN_PATH}/blobfuse-proxy in blobfuse-proxy.service" sed -i "s|/usr/bin/blobfuse-proxy|${BIN_PATH}/blobfuse-proxy|g" /blobfuse-proxy/blobfuse-proxy.service if [ "${BIN_PATH}" != "/usr/local/bin" ]; then - echo "add Environment=\"PATH=${BIN_PATH}:$PATH\" in blobfuse-proxy.service" - sed -i "/Delegate=yes/a Environment=\"PATH=${BIN_PATH}:\$PATH\"" /blobfuse-proxy/blobfuse-proxy.service + echo "add \"PATH=${BIN_PATH}:\$PATH\" in blobfuse-proxy.service ExecStart." + sed "s,^ExecStart[[:space:]]*=\\(.*\\)\$,ExecStart=/usr/bin/bash -c \"PATH=${BIN_PATH}:\$PATH \\1\"," \ + /blobfuse-proxy/blobfuse-proxy.service fi if [ -f "/host/etc/systemd/system/blobfuse-proxy.service" ];then old=$(sha256sum /host/etc/systemd/system/blobfuse-proxy.service | awk '{print $1}') From 1aa762678e90fbff6c21d41145eb42d5ca634937 Mon Sep 17 00:00:00 2001 From: Thilo Fromm Date: Sun, 19 Oct 2025 10:54:02 +0200 Subject: [PATCH 3/3] chore: update helm charts Signed-off-by: Thilo Fromm --- charts/latest/blob-csi-driver-1.27.0.tgz | Bin 6610 -> 6623 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/charts/latest/blob-csi-driver-1.27.0.tgz b/charts/latest/blob-csi-driver-1.27.0.tgz index 4486bffef9aa679de24d83e43bee54853a2e46a5..9c589a093e61f7cf84488fcfd044558448a58a89 100644 GIT binary patch delta 6622 zcmV<486oD2Dn$uf zfNpHdkz{trX1@EsB>CC0F$_Di$>CIG2fNkXl3U#^b+^2*$-*!hHY|!ah&FH5kn+YB zI`%h5yIQSQ>+<|u{@ZG`vj4W)muKI!FIra@?atZx+2uE__J4W%vhxjS9gl_L%V!+Y zZ(2{LmF?VLJ zZe~NEgs0|02X#S4q-vWC!k6yy=}KJL`M-g-kJxb)K>7S{cg{MO+4+CoIX}(+=eV!~ zSEyS9U;!DLB7cu`fn(B!gH1{pS@MQS9P!j93jqZHMIK?86T0n!CSk0(=``>C1)?tE zhzU_@hB77LIa~?NqNcvM;rX^bAvQL*T`*jZ2%k{IkjrZTm<&%S*LMHyg#^#N(pt1*T|;C~{2%I03{( zfKcENiU30`IIi1fP2QjQwmnnabiuE`)m{MuD1+y0 zgO|8{hqel21RYeXF+?}mL_O0azRSfJn-oEgx`0z3fmh&X(G~Ic4tX>S&1)m@DXl%GZb{U3S37{GS!vHrvuo9e#@qZ+qM=1AQ@sJZheHTQN4nPK6;!;95SZo19 zoQo+9#iW<$ZWJ~_VX+110Xm+IKv(?EfONrUfxE{(Fd^#gR;vvjYk8o@S}idpB4N`^ z4I!68J>AIhif45fK%u}4`B0f1s~DPj&_rDzUWlQ_uLgvykxv816QdioiNt?R7=Irj z{)y20NKf!JX3_YV#J4Rmp)Abc!bX-*0x{#jB1nuY2Nv>>YXRbd_p@Qxyat5CQf#sb zp}Y$^|GGRo*IU6gf;L~rV4a#Y5jHj<>jL@9cgOB~DCD856jFHeM)5PTp^M^2HdzUo zx4Ym%;!={#6gi#s7koLGv+$Q--hYwy>7vzokAu4u{q7@{gfcx}NP&}U)(Kl_`ddt_ z{X}B1`&3Nh$0yRr8uKqTba1)EVmb#ZPH6ub5~`KZ;1(w~qJj36SPXEFwp~z{mVy!+ zHPRZ&krGr7C=yS!7TD^82h2DNAE4zDnY;_?BQi7B$ntGeuY^CC9G(!yFMm$OI1-tg zK)?1Zi@0p;+S|i$)}*=4t2%M}#gv?UI&^L9qL0M(9rO-ud!~sP`x*1~&_XVkA{HtR z2R?jo;Ra$`XuK|H>(tmqH8pmYQ$)xWSYO*@vGf_5Q1Y;iI9;UfN`%;D9NKmWA9I;| z)QQl9xo@zIM!u71>0}<%|E1QLs%2mWK6n=7sQ)_I z4zDQW=-rP@E$m`88RAm}t=<|zYli{cz;$6UAQ27S)u+Lr6IH|Bt3cI zb@m~0h&w}4BBK^c)2P*(z!k3Fl;dtF&saW@3#TPsy@y^mxB;TYUJ@{aLakPV7V1ab zo+Z?)vrWS0I;G}_wts74h+`L8(?2<4)jFwWqME*lo6S5-S^o-Jr(h_8mM~qx8>}r6 z8VA!v0We}4FT=6^4j_@N8x!S&@1jyaJJZ0%{jk-2Tob!q~9ye*pc#>kn^#0K?In@eknV-gGn^z5M|U zrql6Mxcy@77MLE%gt!s^uG!f2A4G42nY9t`g60O&ri~ZP;7(220!~R6SZINvTdRph zgiW9o8B}S)F@JLTupf|l1%4%-lAqtea4BW1*Xs*KE*yQeV3sR(YCy*D%0(7%pbJ-G z;St~kSgkm)E88>ZAi$9eT`tym;#RO~lmz)2xxxemAj3ZRg!x*6?MF2rG3*Q765x{E zdg)!&zs{B2|L4f@Y{(I7j>dO`S%W|DC)3y!|2uEBGk^R47nc`Tr~UuuxbDPsFAM64 zsl5tz9xUY9WUFkE+?Wbxb)#0hBfwlE^L__1wUfmm_t_7?vk_znP~Yv=0>x%>8yJQg zE-J1+e+G>yl5mY^sR14z1xpH>^N?{+58N10#L}eVc=Z$}*92vGGww zoCV}~gDAxo0)Gk*&o#m2nfwzw$`J!~BSwZ?OMm_?d8^&X7=q$OaVJ;}QV)a^B11=u zZOpOS%Wu^5j7yN1m`Ab8m!STC%=kZ6Pj^859jxlXpK^;-XsP=DtAqNyen@AC;}GE@ zDaFQ$m<$0_%t2w(>%cDf{27FEJN0fFK-)-eWVohknAM)eEUWlP5x;hVPw^1DrtMor zy?-g-%p{IST=piPQ6(*?LFVNqd4r6 z(0KL9fc`yuai}!$vSSXj@l-)L7h{!;D1UTUsI(o3)~I553wo38*h}l&ujwkb|C*TC zfoVbI_P=v>-p=Izby`Y^?&HY z=ZZvVg}TAkJ2%(22{tP;s$(^8;bN9ARl{)p1>_S0FE?&eob16%)q(pl*Cf{3+0CRz zxRaD@qc+z<&_=jb)0AGzpNnT{??tl%4G78PnB^!#F$;qw$=6%uJ<6X!=6@HVT78xs zxk4Z{h#H>4S0wt|%iWE(vAYUl&DdQHS1yTe4<3-|%e3)C%d{}aF-$)e{+!gh zg9neIAVQdd$W5oR-Y2v{OhJa&D+Tg%jg#?r6|&NDhg?fTc?aK_7gCvHl|b=yRx|3d zNSu?eFtfra*N6aU^2!pkFn{+nxja$`vN>H*j~Ft=(r`k_65A*#GJNZyE|~f*#}4YN zJ&4l&CE}DZ;Z*Q)j~>UXrI;rpk&KbdTn@xz4cUYuxku2fr?q|~oh8+XQ+7d0Y*b!% zO2w)6VV*a5e9S#7!`5<2-fMWzk0qoTM)3{b@B z*1#@DbOUX}fe+VbEq^Boh}=!~RjC;gyo!w8lJV6pXa*VS4MxoStguZIiRioJC{9{W zi_j(+QP1#~41b5k4)LY97knXZSeT}aXPD*!G%jswVG;ml*iAUQ?M|BELhUFn6MArg zZOk#snN*7sFK>u@x3@W+6{h7Fs`8r)Equ_afLEQ~^mULc}$^cVYJ1gXJP3ug?l^#)y!C*32ra_cR(kkFcCNQgnwjeXj z$aX6+FxvFy{V>O_UPbgJUZBjyHIU=+ZHit2dTq*e27j~AvpETkmMAJox{AEUg2Fu*jT;7?aHBh78CIRt)Vvvf*}yOyXLs z3(i_8n18^Ji5|Dpk3B>&vGk3LmlFT^FdfWqri1=qbT{nX&fg4g2fBsD8%mt~mQ$1w z{0?oWXqg8Hr70+#pvW?o*w$?z$-Nx$rnNgZDj748lArBJ(irF$M!t(5y3J;>$C#gm zfmV&vP(i((pMHvgpYHA^v-xB?{`W6>`gv`gz<--TS|BB*99Cg)fByDiFD+DW$MaeL z-TZd^c78kfIJm7!HJ?gcFbqirAapyZ%RIXohvvOh_Ju>C7#xf~4yWVM`@!f=iv6T_ z_fx@|8gVmGK-!cnGC@ZYZv2-KcfSF;8Bczh-;75$AEwj6=;oLC$KLG+?ZoSXdONrC zpnpfBx>2w%Q16sudHvzdo56Jc_H_{x^}SXTQO?7&Z6RbEQ$l#N0skorSDWTxI-J<$^3P=Wh8Y*)g)R)L26xP2l5+}y&lBJgD0b_R4L^QY8ohe1g za$l^1cJW%ms^Q&d-)fd!?;bZzXmIK?-hY(adM3{d?*6C~qeIBUH@}}qtJ(sz>h`vFbNo5By#HaWp=;U5Q0mgauFsHxC?)h-*7N-1 zWjBk%vH#k)iegq@VlD?2dHFb(w)1jbD=R}kKjvC!4c3kp8p|YBJ#uW*%ZJ_ePJhJ= z`8#w z@+9>HpyjgAs)rez;Ywhi?0lMonDt#!C-gNkC-7cG|le%-{Vun@mNqE?C{GBBk73G zu3dGLu);X8aCwb2agdQXYkz^WE>tp3B$_lulVtotG|8`EG7*Y2TPsK{`gSekjj6fVTgU04K&)>+k_(OBxb z>RV)kdV5uyWq&F+;(k0w!u+1OE~m1Rud%G8-C{Y23S}ZvqN^t53Y?qkPHOdA76+He zzsh0>{YP3VNVeuM;^WHqP6BzE(=|Cz*1rVx{pCK+gUNvfepU3+WKxR<`TF|X@A}i> z$H8mgzNiDH64^&fv=NTy6bbH)LcMTi4%y zCl-(M(YQaDk9zM1I?9JubXBOIl01Kj%Bf<+B{frDUkzH7DlX;oSE%1g3(^YlFk_N& z$l0|f|9?PtNO}RI^4ks4*<&0!o?$|BjfDEmvs(0-2R&w~uMIE$=0gr)_M;GGLy6^g zL&A>Vqpbnur$dZSn6C|NAs2JZ^Yg0OM@LErTz*bLb*Et3rXpX5RcfjMDXh`lvxHBB zO}qH2QoI-6KYr!gj#{;JU0mj&w$D`;9Ea4SoqwI`(T-Y=mfa@L*wWot(A()-hroLl-9AmT;%aND(K4A z$J(_gB_3Qs^-=WK*phVuQcvn_t7s$F3tz4TFOA4?vlcY@adzRX>16tERloPwE#K2; zynhsDR_O$Qc)S^X#k(o})~5VStxhVGTbp~F#%SY3(;=2`qwK2*!wU;T|NOY+i?59eox*uc6C{PE;Yd zZ@_$yV0md#+Diw`cLdB!c`pf^mjumAQGX^ucLvUPVaf#1OM>US>IM@y%0QnK)kv@J zca(dU_>zaScn}8#uH=&kY97Q`67aB@S`r;YcL`MW3@xi$|g7d@2I2 z#L~V+!27$uJA|x~6|F99IV)?FdcdWu6*<*a>d*D1D%$j+y>g9m^)aV1?Z53+Tz~&b z7tl10@)4jN_1~9gSDEksb=p_$_No5!Ij+o17B9V_jun?5?h1;()n`7Z#73zCQ3(xw zz9tm^Ax(dxZoIT=RJIHpF#|ntL|tenkHVKt0mj9js0Qpber639v%E{(l3g+nC9JGap~gx4<%PE_;Z-4t-~h_&8nZOB-~4p;0G+8~!7FoZ#GqQN|69!y`=m07Bcvws$QWBYuF zs7h_RP&+}CDzE#VqR2wAC>i&nm-j_=ZgAq-UqRniP!UJgvQMJWRNuMI5<0LKdcFEI zh5GE;Nyzte>!#xf_}@S&Wd@?MLOQBG5^tpNZAF6t@Fr2je@vmb29|!zS|r9{>RV|MgKg$pE$h0F*ZuX#fBK delta 6609 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