Skip to content

Commit bb31c9b

Browse files
authored
Merge pull request #869 from leiyiz/rox-fix
pdcsi rox workflow fix
2 parents 775e0af + 05e6481 commit bb31c9b

File tree

9 files changed

+141
-7
lines changed

9 files changed

+141
-7
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
apiVersion: builtin
2+
kind: ImageTagTransformer
3+
metadata:
4+
name: imagetag-csi-provisioner-alpha
5+
imageTag:
6+
name: k8s.gcr.io/sig-storage/csi-provisioner
7+
newTag: "v3.0.0"

deploy/kubernetes/images/alpha/kustomization.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ namespace:
22
gce-pd-csi-driver
33
resources:
44
- ../stable-master/
5+
- image.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
kind: Deployment
2+
apiVersion: apps/v1
3+
metadata:
4+
name: csi-gce-pd-controller
5+
spec:
6+
template:
7+
spec:
8+
containers:
9+
- name: csi-provisioner
10+
args:
11+
- "--v=5"
12+
- "--csi-address=/csi/csi.sock"
13+
- "--feature-gates=Topology=true"
14+
- "--http-endpoint=:22011"
15+
- "--leader-election-namespace=$(PDCSI_NAMESPACE)"
16+
- "--timeout=250s"
17+
- "--extra-create-metadata"
18+
- "--leader-election"
19+
- "--default-fstype=ext4"
20+
- "--controller-publish-readonly=true"

deploy/kubernetes/overlays/alpha/kustomization.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@ kind: Kustomization
33
namespace: gce-pd-csi-driver
44
resources:
55
- ../../base/
6+
patchesStrategicMerge:
7+
- controller_readonly.yaml
68
transformers:
79
- ../../images/alpha

pkg/gce-pd-csi-driver/controller.go

+5
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,12 @@ func (gceCS *GCEControllerServer) CreateVolume(ctx context.Context, req *csi.Cre
252252
return nil, status.Error(codes.Internal, fmt.Sprintf("CreateVolume disk from source volume %v is not ready", sourceVolKey))
253253
}
254254
}
255+
} else { // if VolumeContentSource is nil, validate access mode is not read only
256+
if readonly, _ := getReadOnlyFromCapabilities(volumeCapabilities); readonly {
257+
return nil, status.Error(codes.InvalidArgument, "VolumeContentSource must be provided when AccessMode is set to read only")
258+
}
255259
}
260+
256261
// Create the disk
257262
var disk *gce.CloudDisk
258263
switch params.ReplicationType {

pkg/gce-pd-csi-driver/controller_test.go

+2-7
Original file line numberDiff line numberDiff line change
@@ -358,19 +358,14 @@ func TestCreateVolumeArguments(t *testing.T) {
358358
},
359359
},
360360
{
361-
name: "success with MULTI_NODE_READER_ONLY",
361+
name: "fail with MULTI_NODE_READER_ONLY",
362362
req: &csi.CreateVolumeRequest{
363363
Name: "test-name",
364364
CapacityRange: stdCapRange,
365365
VolumeCapabilities: createVolumeCapabilities(csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY),
366366
Parameters: stdParams,
367367
},
368-
expVol: &csi.Volume{
369-
CapacityBytes: common.GbToBytes(20),
370-
VolumeId: testVolumeID,
371-
VolumeContext: nil,
372-
AccessibleTopology: stdTopology,
373-
},
368+
expErrCode: codes.InvalidArgument,
374369
},
375370
{
376371
name: "fail with mount/MULTI_NODE_MULTI_WRITER capabilities",

pkg/gce-pd-csi-driver/node.go

+22
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ const (
6060
volumeLimitBig int64 = 127
6161
defaultLinuxFsType = "ext4"
6262
defaultWindowsFsType = "ntfs"
63+
fsTypeExt3 = "ext3"
6364
)
6465

6566
func getDefaultFsType() string {
@@ -311,8 +312,29 @@ func (ns *GCENodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStage
311312
return &csi.NodeStageVolumeResponse{}, nil
312313
}
313314

315+
readonly, _ := getReadOnlyFromCapability(volumeCapability)
316+
if readonly {
317+
options = append(options, "ro")
318+
klog.V(4).Infof("CSI volume is read-only, mounting with extra option ro")
319+
}
320+
314321
err = formatAndMount(devicePath, stagingTargetPath, fstype, options, ns.Mounter)
315322
if err != nil {
323+
// If a volume is created from a content source like snapshot or cloning, the filesystem might get marked
324+
// as "dirty" even if it is otherwise consistent and ext3/4 will try to restore to a consistent state by replaying
325+
// the journal which is not possible in read-only mode. So we'll try again with noload option to skip it. This may
326+
// allow mounting of an actually inconsistent filesystem, but because the mount is read-only no further damage should
327+
// be caused.
328+
if readonly && (fstype == defaultLinuxFsType || fstype == fsTypeExt3) {
329+
klog.V(4).Infof("Failed to mount CSI volume read-only, retry mounting with extra option noload")
330+
331+
options = append(options, "noload")
332+
err = formatAndMount(devicePath, stagingTargetPath, fstype, options, ns.Mounter)
333+
if err == nil {
334+
klog.V(4).Infof("NodeStageVolume succeeded with \"noload\" option on %v to %s", volumeID, stagingTargetPath)
335+
return &csi.NodeStageVolumeResponse{}, nil
336+
}
337+
}
316338
return nil, status.Error(codes.Internal,
317339
fmt.Sprintf("Failed to format and mount device from (%q) to (%q) with fstype (%q) and options (%q): %v",
318340
devicePath, stagingTargetPath, fstype, options, err))

pkg/gce-pd-csi-driver/utils.go

+25
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,31 @@ func getMultiWriterFromCapabilities(vcs []*csi.VolumeCapability) (bool, error) {
160160
return false, nil
161161
}
162162

163+
func getReadOnlyFromCapability(vc *csi.VolumeCapability) (bool, error) {
164+
if vc.GetAccessMode() == nil {
165+
return false, errors.New("access mode is nil")
166+
}
167+
mode := vc.GetAccessMode().GetMode()
168+
return (mode == csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY ||
169+
mode == csi.VolumeCapability_AccessMode_SINGLE_NODE_READER_ONLY), nil
170+
}
171+
172+
func getReadOnlyFromCapabilities(vcs []*csi.VolumeCapability) (bool, error) {
173+
if vcs == nil {
174+
return false, errors.New("volume capabilities is nil")
175+
}
176+
for _, vc := range vcs {
177+
readOnly, err := getReadOnlyFromCapability(vc)
178+
if err != nil {
179+
return false, err
180+
}
181+
if readOnly {
182+
return true, nil
183+
}
184+
}
185+
return false, nil
186+
}
187+
163188
func collectMountOptions(fsType string, mntFlags []string) []string {
164189
var options []string
165190

pkg/gce-pd-csi-driver/utils_test.go

+57
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,60 @@ func TestGetMultiWriterFromCapabilities(t *testing.T) {
234234
}
235235
}
236236
}
237+
238+
func TestGetReadOnlyFromCapabilities(t *testing.T) {
239+
testCases := []struct {
240+
name string
241+
vc []*csi.VolumeCapability
242+
expVal bool
243+
expErr bool
244+
}{
245+
{
246+
name: "false with empty capabilities",
247+
vc: []*csi.VolumeCapability{},
248+
expVal: false,
249+
},
250+
{
251+
name: "fail with capabilities no access mode",
252+
vc: []*csi.VolumeCapability{
253+
{
254+
AccessType: &csi.VolumeCapability_Mount{
255+
Mount: &csi.VolumeCapability_MountVolume{},
256+
},
257+
},
258+
},
259+
expErr: true,
260+
},
261+
{
262+
name: "false with SINGLE_NODE_WRITER capabilities",
263+
vc: createVolumeCapabilities(csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
264+
expVal: false,
265+
},
266+
{
267+
name: "true with MULTI_NODE_READER_ONLY capabilities",
268+
vc: createBlockVolumeCapabilities(csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY),
269+
expVal: true,
270+
},
271+
{
272+
name: "true with SINGLE_NODE_READER_ONLY capabilities",
273+
vc: createVolumeCapabilities(csi.VolumeCapability_AccessMode_SINGLE_NODE_READER_ONLY),
274+
expVal: true,
275+
},
276+
}
277+
278+
for _, tc := range testCases {
279+
t.Logf("Running test: %v", tc.name)
280+
val, err := getReadOnlyFromCapabilities(tc.vc)
281+
if tc.expErr && err == nil {
282+
t.Fatalf("Expected error but didn't get any")
283+
}
284+
if !tc.expErr && err != nil {
285+
t.Fatalf("Did not expect error but got: %v", err)
286+
}
287+
if err != nil {
288+
if tc.expVal != val {
289+
t.Fatalf("Expected '%t' but got '%t'", tc.expVal, val)
290+
}
291+
}
292+
}
293+
}

0 commit comments

Comments
 (0)