Skip to content

Commit 7b70c0b

Browse files
authored
Merge pull request #788 from cvvz/support-blobfuse2
feat: support fuse2 protocol in storageclass
2 parents 23f7ecf + 09f8eb2 commit 7b70c0b

11 files changed

+97
-38
lines changed

docs/driver-parameters.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ skuName | Azure storage account type (alias: `storageAccountType`) | `Standard_L
1212
location | Azure location | `eastus`, `westus`, etc. | No | if empty, driver will use the same location name as current k8s cluster
1313
resourceGroup | Azure resource group name | existing resource group name | No | if empty, driver will use the same resource group name as current k8s cluster
1414
storageAccount | specify Azure storage account name| STORAGE_ACCOUNT_NAME | - No for blobfuse mount </br> - Yes for NFSv3 mount | - For blobfuse mount: if empty, driver will find a suitable storage account that matches `skuName` in the same resource group; if a storage account name is provided, storage account must exist. </br> - For NFSv3 mount, storage account name must be provided
15-
protocol | specify blobfuse mount or NFSv3 mount | `fuse`, `nfs` | No | `fuse`
15+
protocol | specify blobfuse, blobfuse2 or NFSv3 mount (blobfuse2 is still in Preview) | `fuse`, `fuse2`, `nfs` | No | `fuse`
1616
containerName | specify the existing container(directory) name | existing container name | No | if empty, driver will create a new container name, starting with `pvc-fuse` for blobfuse or `pvc-nfs` for NFSv3
1717
containerNamePrefix | specify Azure storage directory prefix created by driver | can only contain lowercase letters, numbers, hyphens, and length should be less than 21 | No |
1818
server | specify Azure storage account server address | existing server address, e.g. `accountname.privatelink.blob.core.windows.net` | No | if empty, driver will use default `accountname.blob.core.windows.net` or other sovereign cloud account address
@@ -70,7 +70,7 @@ Name | Meaning | Available Value | Mandatory | Default value
7070
volumeAttributes.resourceGroup | Azure resource group name | existing resource group name | No | if empty, driver will use the same resource group name as current k8s cluster
7171
volumeAttributes.storageAccount | existing storage account name | existing storage account name | Yes |
7272
volumeAttributes.containerName | existing container name | existing container name | Yes |
73-
volumeAttributes.protocol | specify blobfuse mount or NFSv3 mount | `fuse`, `nfs` | No | `fuse`
73+
volumeAttributes.protocol | specify blobfuse, blobfuse2 or NFSv3 mount (blobfuse2 is still in Preview) | `fuse`, `fuse2`, `nfs` | No | `fuse`
7474
--- | **Following parameters are only for blobfuse** | --- | --- |
7575
volumeAttributes.secretName | secret name that stores storage account name and key(only applies for SMB) | | No |
7676
volumeAttributes.secretNamespace | secret namespace | `default`,`kube-system`, etc | No | pvc namespace

pkg/blob/blob.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,9 @@ const (
8585
trueValue = "true"
8686
defaultSecretAccountName = "azurestorageaccountname"
8787
defaultSecretAccountKey = "azurestorageaccountkey"
88-
fuse = "fuse"
89-
nfs = "nfs"
88+
Fuse = "fuse"
89+
Fuse2 = "fuse2"
90+
NFS = "nfs"
9091
vnetResourceGroupField = "vnetresourcegroup"
9192
vnetNameField = "vnetname"
9293
subnetNameField = "subnetname"
@@ -124,7 +125,7 @@ const (
124125
)
125126

126127
var (
127-
supportedProtocolList = []string{fuse, nfs}
128+
supportedProtocolList = []string{Fuse, Fuse2, NFS}
128129
retriableErrors = []string{accountNotProvisioned, tooManyRequests, statusCodeNotFound, containerBeingDeletedDataplaneAPIError, containerBeingDeletedManagementAPIError, clientThrottled}
129130
)
130131

@@ -409,7 +410,7 @@ func (d *Driver) GetAuthEnv(ctx context.Context, volumeID, protocol string, attr
409410
}
410411
klog.V(2).Infof("volumeID(%s) authEnv: %s", volumeID, authEnv)
411412

412-
if protocol == nfs {
413+
if protocol == NFS {
413414
// nfs protocol does not need account key, return directly
414415
return rgName, accountName, accountKey, containerName, authEnv, err
415416
}

pkg/blob/blob_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ func TestGetAuthEnv(t *testing.T) {
585585
volumeID := "unique-volumeid"
586586
attrib[storageAccountField] = "accountname"
587587
attrib[containerNameField] = "containername"
588-
rg, accountName, accountkey, containerName, authEnv, err := d.GetAuthEnv(context.TODO(), volumeID, nfs, attrib, secret)
588+
rg, accountName, accountkey, containerName, authEnv, err := d.GetAuthEnv(context.TODO(), volumeID, NFS, attrib, secret)
589589
if err != nil {
590590
t.Errorf("actualErr: (%v), expect no error", err)
591591
}

pkg/blob/controllerserver.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
163163
}
164164

165165
if subsID != "" && subsID != d.cloud.SubscriptionID {
166-
if protocol == nfs {
166+
if protocol == NFS {
167167
return nil, status.Errorf(codes.InvalidArgument, fmt.Sprintf("NFS protocol is not supported in cross subscription(%s)", subsID))
168168
}
169169
if !storeAccountKey {
@@ -184,7 +184,7 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
184184
}
185185

186186
if protocol == "" {
187-
protocol = fuse
187+
protocol = Fuse
188188
}
189189
if !isSupportedProtocol(protocol) {
190190
return nil, status.Errorf(codes.InvalidArgument, "protocol(%s) is not supported, supported protocol list: %v", protocol, supportedProtocolList)
@@ -206,7 +206,7 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
206206
vnetResourceIDs []string
207207
enableNfsV3 *bool
208208
)
209-
if protocol == nfs {
209+
if protocol == NFS {
210210
isHnsEnabled = to.BoolPtr(true)
211211
enableNfsV3 = to.BoolPtr(true)
212212
// set VirtualNetworkResourceIDs for storage account firewall setting

pkg/blob/controllerserver_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ func TestCreateVolume(t *testing.T) {
237237
controllerServiceCapability,
238238
}
239239
_, err := d.CreateVolume(context.Background(), req)
240-
expectedErr := status.Errorf(codes.InvalidArgument, "protocol(unit-test) is not supported, supported protocol list: [fuse nfs]")
240+
expectedErr := status.Errorf(codes.InvalidArgument, "protocol(unit-test) is not supported, supported protocol list: [fuse fuse2 nfs]")
241241
if !reflect.DeepEqual(err, expectedErr) {
242242
t.Errorf("actualErr: (%v), expectedErr: (%v)", err, expectedErr)
243243
}

pkg/blob/nodeserver.go

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ func (d *Driver) NodePublishVolume(ctx context.Context, req *csi.NodePublishVolu
140140
return &csi.NodePublishVolumeResponse{}, nil
141141
}
142142

143-
func (d *Driver) mountBlobfuseWithProxy(args string, authEnv []string) (string, error) {
143+
func (d *Driver) mountBlobfuseWithProxy(args string, protocol string, authEnv []string) (string, error) {
144144
klog.V(2).Infof("mouting using blobfuse proxy")
145145
var resp *mount_azure_blob.MountAzureBlobResponse
146146
var output string
@@ -152,6 +152,7 @@ func (d *Driver) mountBlobfuseWithProxy(args string, authEnv []string) (string,
152152
mountClient := NewMountClient(conn)
153153
mountreq := mount_azure_blob.MountAzureBlobRequest{
154154
MountArgs: args,
155+
Protocol: protocol,
155156
AuthEnv: authEnv,
156157
}
157158
klog.V(2).Infof("calling BlobfuseProxy: MountAzureBlob function")
@@ -164,11 +165,23 @@ func (d *Driver) mountBlobfuseWithProxy(args string, authEnv []string) (string,
164165
return output, err
165166
}
166167

167-
func (d *Driver) mountBlobfuseInsideDriver(args string, authEnv []string) (string, error) {
168+
func (d *Driver) mountBlobfuseInsideDriver(args string, protocol string, authEnv []string) (string, error) {
169+
var cmd *exec.Cmd
170+
168171
klog.V(2).Infof("mounting blobfuse inside driver")
169-
cmd := exec.Command("blobfuse", strings.Split(args, " ")...)
172+
if protocol == Fuse2 {
173+
klog.V(2).Infof("using blobfuse V2 to mount")
174+
args = "mount " + args
175+
cmd = exec.Command("blobfuse2", strings.Split(args, " ")...)
176+
} else {
177+
klog.V(2).Infof("using blobfuse V1 to mount")
178+
cmd = exec.Command("blobfuse", strings.Split(args, " ")...)
179+
}
180+
170181
cmd.Env = append(os.Environ(), authEnv...)
171182
output, err := cmd.CombinedOutput()
183+
klog.V(2).Infof("mount output: %s\n", string(output))
184+
172185
return string(output), err
173186
}
174187

@@ -290,14 +303,14 @@ func (d *Driver) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRe
290303
serverAddress = fmt.Sprintf("%s.blob.%s", accountName, storageEndpointSuffix)
291304
}
292305

293-
if protocol == nfs {
306+
if protocol == NFS {
294307
klog.V(2).Infof("target %v\nprotocol %v\n\nvolumeId %v\ncontext %v\nmountflags %v\nserverAddress %v",
295308
targetPath, protocol, volumeID, attrib, mountFlags, serverAddress)
296309

297310
source := fmt.Sprintf("%s:/%s/%s", serverAddress, accountName, containerName)
298311
mountOptions := util.JoinMountOptions(mountFlags, []string{"sec=sys,vers=3,nolock"})
299312
if err := wait.PollImmediate(1*time.Second, 2*time.Minute, func() (bool, error) {
300-
return true, d.mounter.MountSensitive(source, targetPath, nfs, mountOptions, []string{})
313+
return true, d.mounter.MountSensitive(source, targetPath, NFS, mountOptions, []string{})
301314
}); err != nil {
302315
return nil, status.Error(codes.Internal, fmt.Sprintf("volume(%s) mount %q on %q failed with %v", volumeID, source, targetPath, err))
303316
}
@@ -348,9 +361,9 @@ func (d *Driver) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRe
348361

349362
var output string
350363
if d.enableBlobfuseProxy {
351-
output, err = d.mountBlobfuseWithProxy(args, authEnv)
364+
output, err = d.mountBlobfuseWithProxy(args, protocol, authEnv)
352365
} else {
353-
output, err = d.mountBlobfuseInsideDriver(args, authEnv)
366+
output, err = d.mountBlobfuseInsideDriver(args, protocol, authEnv)
354367
}
355368

356369
if err != nil {

pkg/blob/nodeserver_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -741,7 +741,7 @@ func TestMountBlobfuseWithProxy(t *testing.T) {
741741
args := "--tmp-path /tmp"
742742
authEnv := []string{"username=blob", "authkey=blob"}
743743
d := NewFakeDriver()
744-
_, err := d.mountBlobfuseWithProxy(args, authEnv)
744+
_, err := d.mountBlobfuseWithProxy(args, "fuse", authEnv)
745745
// should be context.deadlineExceededError{} error
746746
assert.NotNil(t, err)
747747
}
@@ -750,7 +750,7 @@ func TestMountBlobfuseInsideDriver(t *testing.T) {
750750
args := "--tmp-path /tmp"
751751
authEnv := []string{"username=blob", "authkey=blob"}
752752
d := NewFakeDriver()
753-
_, err := d.mountBlobfuseInsideDriver(args, authEnv)
753+
_, err := d.mountBlobfuseInsideDriver(args, Fuse, authEnv)
754754
// the error should be of type exec.ExitError
755755
assert.NotNil(t, err)
756756
}

pkg/blobfuse-proxy/pb/azure_blob_mount.pb.go

Lines changed: 22 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/blobfuse-proxy/proto/azure_blob_mount.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ option go_package = ".;pb";
55
message MountAzureBlobRequest {
66
string mountArgs = 1;
77
repeated string authEnv = 2;
8+
string protocol = 3;
89
}
910

1011
message MountAzureBlobResponse {

pkg/blobfuse-proxy/server/server.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626

2727
"google.golang.org/grpc"
2828
"k8s.io/klog/v2"
29+
"sigs.k8s.io/blob-csi-driver/pkg/blob"
2930
mount_azure_blob "sigs.k8s.io/blob-csi-driver/pkg/blobfuse-proxy/pb"
3031
"sigs.k8s.io/blob-csi-driver/pkg/util"
3132
)
@@ -62,16 +63,18 @@ func (server *MountServer) MountAzureBlob(ctx context.Context,
6263

6364
args := req.GetMountArgs()
6465
authEnv := req.GetAuthEnv()
65-
klog.V(2).Infof("received mount request: Mounting with args %v \n", args)
66+
protocol := req.GetProtocol()
67+
klog.V(2).Infof("received mount request: Protocol: %s, server default blobfuseVersion: %v, Mounting with args %v \n", protocol, server.blobfuseVersion, args)
6668

6769
var cmd *exec.Cmd
6870
var result mount_azure_blob.MountAzureBlobResponse
69-
switch server.blobfuseVersion {
70-
case BlobfuseV1:
71-
cmd = exec.Command("blobfuse", strings.Split(args, " ")...)
72-
case BlobfuseV2:
71+
if protocol == blob.Fuse2 || server.blobfuseVersion == BlobfuseV2 {
72+
klog.V(2).Infof("using blobfuse V2 to mount")
7373
args = "mount " + args
7474
cmd = exec.Command("blobfuse2", strings.Split(args, " ")...)
75+
} else {
76+
klog.V(2).Infof("using blobfuse V1 to mount")
77+
cmd = exec.Command("blobfuse", strings.Split(args, " ")...)
7578
}
7679

7780
cmd.Env = append(cmd.Env, authEnv...)
@@ -111,9 +114,10 @@ func getBlobfuseVersion() BlobfuseVersion {
111114
}
112115

113116
if osinfo.Distro == "Ubuntu" && osinfo.Version >= "22.04" {
114-
klog.V(2).Info("proxy using blobfuse V2 for mounting")
117+
klog.V(2).Info("proxy default using blobfuse V2 for mounting")
115118
return BlobfuseV2
116119
}
117120

121+
klog.V(2).Info("proxy default using blobfuse V1 for mounting")
118122
return BlobfuseV1
119123
}

test/e2e/dynamic_provisioning_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,4 +571,34 @@ var _ = ginkgo.Describe("[blob-csi-e2e] Dynamic Provisioning", func() {
571571
}
572572
test.Run(cs, ns)
573573
})
574+
575+
ginkgo.It("should create a blobfuse2 volume on demand with mount options [fuse2]", func() {
576+
if isAzureStackCloud {
577+
ginkgo.Skip("test case is not available for Azure Stack")
578+
}
579+
pods := []testsuites.PodDetails{
580+
{
581+
Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data",
582+
Volumes: []testsuites.VolumeDetails{
583+
{
584+
ClaimSize: "10Gi",
585+
MountOptions: []string{},
586+
VolumeMount: testsuites.VolumeMountDetails{
587+
NameGenerate: "test-volume-",
588+
MountPathGenerate: "/mnt/test-",
589+
},
590+
},
591+
},
592+
},
593+
}
594+
test := testsuites.DynamicallyProvisionedCmdVolumeTest{
595+
CSIDriver: testDriver,
596+
Pods: pods,
597+
StorageClassParameters: map[string]string{
598+
"skuName": "Standard_LRS",
599+
"protocol": "fuse2",
600+
},
601+
}
602+
test.Run(cs, ns)
603+
})
574604
})

0 commit comments

Comments
 (0)