Change:
<!-- This form is for bug reports and feature requests ONLY! If you're looking for help check and the . If this may be security issue, please disclose it privately via --Is this a BUG REPORT or FEATURE REQUEST?: What happened: When use ceph as storageclass, i set accessModes: ReadOnlyMany, and create pods using the claim, only one pod would be running and the others on different nodes would get stuck on ContainerCreating. But if the pods are all on same node, it works fine. What you expected to happen: Pods on different nodes can mount ceph rbd volume. How to reproduce it (as minimally and precisely as possible): Anything else we need to know?: Environment: Kubernetes version (use ): v1.9.2 Cloud provider or hardware configuration: OS (e.g. from /etc/os-release): 3.10.0-327.18.2.el7.x86_64 Kernel (e.g. ): CentOS Linux release 7.2.1511 (Core) Install tools: kubeadm Others:
/sig storage
/assign
, how would this work? For example, how do you put the initial contents of the RBD volume on it if it is in the ReadOnlyMany access mode? How would you use this feature? As a cheap way of sharing files across a Kubernetes cluster? I'm just interested. -ben england
Do we really want to support ? I have the same questions as mentioned above. If we set the PVC AccessMode to , then the field in will need to be set true ? If so, for the first time, in , we will mount the device without formatting, is that intended ? We need to format the device manually before we use it ? /cc FYI: also there is an issue related to this:
We have this same problem for GCE PD, which supports ReadOnlyMany. You need to mount the volume first as RWO, in order to format the filesystem and populate it with data (mounting a read only volume with no data on it seems pointless). Then you have to fully unmount/detach it, and then you can deploy pods using it as ROX. Basically, you can dynamically provision it in RWO to format + populate data. But afterwards, you need to manually create a different PV/PVC for ROX
continuation

Discussion:
if err != nil { return nil, err } <ins> ams, err := getVolumeAccessModes(spec) if err != nil { return nil, err } </ins> secretName, secretNs, err := getSecretNameAndNamespace(spec, pod.Namespace) if err != nil {

} return &rbdMounter{ <del> rbd:     newRBD("", spec.Name(), img, pool, ro, plugin, &RBDUtil{}), Mon:     mon, Id:      id, Keyring: keyring, Secret:  secret, fsType:  fstype, </del> <ins> rbd:         newRBD("", spec.Name(), img, pool, ro, plugin, &RBDUtil{}), Mon:         mon, Id:          id, Keyring:     keyring, Secret:      secret, fsType:      fstype, accessModes: ams, </ins> }, nil }

if err != nil { return nil, err } <ins> ams, err := getVolumeAccessModes(spec) if err != nil { return nil, err } </ins> return &rbdMounter{ rbd:          newRBD(podUID, spec.Name(), img, pool, ro, plugin, manager),

Secret:       secret, fsType:       fstype, mountOptions: volutil.MountOptionFromSpec(spec), <ins> accessModes:  ams, </ins> }, nil }

mountOptions  []string imageFormat   string imageFeatures []string <ins> accessModes   []v1.PersistentVolumeAccessMode </ins> } var _ volume.Mounter = &rbdMounter{}

return false, fmt.Errorf("Spec does not reference a RBD volume type") } <ins> func getVolumeAccessModes(spec *volume.Spec) ([]v1.PersistentVolumeAccessMode, error) { // Only PersistentVolumeSpec has AccessModes if spec.PersistentVolume != nil { if spec.PersistentVolume.Spec.RBD != nil { return spec.PersistentVolume.Spec.AccessModes, nil } else { return nil, fmt.Errorf("Spec does not reference a RBD volume type") } } return nil, nil } </ins> func parsePodSecret(pod *v1.Pod, secretName string, kubeClient clientset.Interface) (string, error) { secret, err := volutil.GetSecretForPod(pod, secretName, kubeClient) if err != nil {

FSType:       "ext4", }, }, <ins> AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadOnlyMany}, </ins> }, }, false), root: tmpDir,

Factor:   rbdImageWatcherFactor, Steps:    rbdImageWatcherSteps, } <ins> needValidUsed := true // If accessModes contain ReadOnlyMany, we don't need check rbd status of being used. if b.accessModes != nil { for _, v := range b.accessModes { if v != v1.ReadWriteOnce { needValidUsed = false break } } } </ins> err := wait.ExponentialBackoff(backoff, func() (bool, error) { used, rbdOutput, err := util.rbdStatus(&b) if err != nil { return false, fmt.Errorf("fail to check rbd image status with: (%v), rbd output: (%s)", err, rbdOutput) } <del> return !used, nil </del> <ins> return !needValidUsed || !used, nil </ins> }) // Return error if rbd image has not become available for the specified timeout. if err == wait.ErrWaitTimeout {