Change:
fyi When using PV/PVC for Persistent Volume volume mounts, if something goes wrong in the builder, a generic error is surfaced in the 'kubectl describe' with the following event error description *unsupported volume type": This only occurs when using the PV/PVC abstraction and not directly using a volume plugin. These type of errors are common when using volume plugins for mounts and would be useful for users to have an easy way to identify the errors rather than searching the logs for root cause. I think there are two issues: Why is the original error surfaced from the volume plugins (, , etc...) getting eaten when they return back to the I can see in the logs that 2 volume types are processed for any pod - the first is the actual underlying type (i.e. ) and this is where the actual real error is surfaced, then immediately after this the 2nd type is processed which is the general persistent claim type (i.e. ) and this when the first type error is eaten A simple work around would be to simply add a recorder event in the when there is a builder failure. This ensures the error is recorded and displayed as an event for the describer and will handle all like errors from other volume plugin types. full modifed function for reference from This will produce a better user experience when trying to see what went wrong - in this example, I am doing glusterfs PV/PVC but am missing end points which you can clearly see now in the events of the describe: rbd example: (Missing or Couldn't get secret)
I haven't had a chance to look at your proposal in detail yet, but I agree this is one of the most confusing things new users hit
another one is when gluster endpoints are missing, we get 'unsupported volume type' with your work extrapolating the permissions for NFS to automatically set supplemental groups, is there also a way to indicate more properly it's a permissions issue for it not mounting?
- the above discussion highlights the missing endpoints as the first example, it also discusses a similar rbd issue (missing secret file) but the point is, any of those type of volume plugin type of errors would be surfaced by adding the event in the
I like it! Is there a PR?

Discussion:
"k8s.io/kubernetes/pkg/volume" ) <del> var errUnsupportedVolumeType = fmt.Errorf("unsupported volume type") </del> // This just exports required functions from kubelet proper, for use by volume // plugins. type volumeHost struct {

return vh.kubelet.kubeClient } <ins> // NewWrapperMounter attempts to create a volume mounter // from a volume Spec, pod and volume options. // Returns a new volume Mounter or an error. </ins> func (vh *volumeHost) NewWrapperMounter(volName string, spec volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Mounter, error) { // The name of wrapper volume is set to "wrapped_{wrapped_volume_name}" wrapperVolumeName := "wrapped_" + volName

spec.Volume.Name = wrapperVolumeName } <del> b, err := vh.kubelet.newVolumeMounterFromPlugins(&spec, pod, opts) if err == nil && b == nil { return nil, errUnsupportedVolumeType } return b, nil </del> <ins> return vh.kubelet.newVolumeMounterFromPlugins(&spec, pod, opts) </ins> } <ins> // NewWrapperUnmounter attempts to create a volume unmounter // from a volume name and pod uid. // Returns a new volume Unmounter or an error. </ins> func (vh *volumeHost) NewWrapperUnmounter(volName string, spec volume.Spec, podUID types.UID) (volume.Unmounter, error) { // The name of wrapper volume is set to "wrapped_{wrapped_volume_name}" wrapperVolumeName := "wrapped_" + volName

if err != nil { return nil, err } <del> if plugin == nil { // Not found but not an error return nil, nil } c, err := plugin.NewUnmounter(spec.Name(), podUID) if err == nil && c == nil { return nil, errUnsupportedVolumeType } return c, nil </del> <ins> return plugin.NewUnmounter(spec.Name(), podUID) </ins> } func (vh *volumeHost) GetCloudProvider() cloudprovider.Interface {

glog.Errorf("Could not create volume mounter for pod %s: %v", pod.UID, err) return nil, err } <del> if mounter == nil { return nil, errUnsupportedVolumeType } </del> // some volumes require attachment before mounter's setup. // The plugin can be nil, but non-nil errors are legitimate errors.

glog.Errorf("Could not create volume unmounter for %s: %v", volume.Name, err) continue } <del> if unmounter == nil { glog.Errorf("Could not create volume unmounter for %s: %v", volume.Name, errUnsupportedVolumeType) continue } </del> tuple := cleanerTuple{Unmounter: unmounter} detacher, err := kl.newVolumeDetacherFromPlugins(volume.Kind, volume.Name, podUID)

return currentVolumes } <ins> // newVolumeMounterFromPlugins attempts to find a plugin by volume spec, pod // and volume options and then creates a Mounter. // Returns a valid Unmounter or an error. </ins> func (kl *Kubelet) newVolumeMounterFromPlugins(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Mounter, error) { plugin, err := kl.volumePluginMgr.FindPluginBySpec(spec) if err != nil { return nil, fmt.Errorf("can't use volume plugins for %s: %v", spec.Name(), err) } <del> if plugin == nil { // Not found but not an error return nil, nil } </del> physicalMounter, err := plugin.NewMounter(spec, pod, opts) if err != nil { <del> return nil, fmt.Errorf("failed to instantiate volume physicalMounter for %s: %v", spec.Name(), err) </del> <ins> return nil, fmt.Errorf("failed to instantiate mounter for volume: %s using plugin: %s with a root cause: %v", spec.Name(), plugin.Name(), err) </ins> } glog.V(10).Infof("Used volume plugin %q to mount %s", plugin.Name(), spec.Name()) return physicalMounter, nil } <ins> // newVolumeAttacherFromPlugins attempts to find a plugin from a volume spec // and then create an Attacher. // Returns: //  - an attacher if one exists //  - an error if no plugin was found for the volume //    or the attacher failed to instantiate //  - nil if there is no appropriate attacher for this volume </ins> func (kl *Kubelet) newVolumeAttacherFromPlugins(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Attacher, error) { plugin, err := kl.volumePluginMgr.FindAttachablePluginBySpec(spec) if err != nil {

return attacher, nil } <ins> // newVolumeUnmounterFromPlugins attempts to find a plugin by name and then // create an Unmounter. // Returns a valid Unmounter or an error. </ins> func (kl *Kubelet) newVolumeUnmounterFromPlugins(kind string, name string, podUID types.UID) (volume.Unmounter, error) { plugName := strings.UnescapeQualifiedNameForDisk(kind) plugin, err := kl.volumePluginMgr.FindPluginByName(plugName)

// TODO: Maybe we should launch a cleanup of this dir? return nil, fmt.Errorf("can't use volume plugins for %s/%s: %v", podUID, kind, err) } <del> if plugin == nil { // Not found but not an error. return nil, nil } </del> unmounter, err := plugin.NewUnmounter(name, podUID) if err != nil { return nil, fmt.Errorf("failed to instantiate volume plugin for %s/%s: %v", podUID, kind, err)

return unmounter, nil } <ins> // newVolumeDetacherFromPlugins attempts to find a plugin by a name and then // create a Detacher. // Returns: //  - a detacher if one exists //  - an error if no plugin was found for the volume //    or the detacher failed to instantiate //  - nil if there is no appropriate detacher for this volume </ins> func (kl *Kubelet) newVolumeDetacherFromPlugins(kind string, name string, podUID types.UID) (volume.Detacher, error) { plugName := strings.UnescapeQualifiedNameForDisk(kind) plugin, err := kl.volumePluginMgr.FindAttachablePluginByName(plugName)