func (pm *VolumePluginMgr) FindPluginByName(name string) (VolumePlugin, error) {
	pm.mutex.Lock()
	defer pm.mutex.Unlock()
	matchedPluginNames := []string{}
	matches := []VolumePlugin{}
	for k, v := range pm.plugins {
		if v.GetPluginName() == name {
			matchedPluginNames = append(matchedPluginNames, k)
			matches = append(matches, v)
		}
	}
	pm.refreshProbedPlugins()
	for _, plugin := range pm.probedPlugins {
		if plugin.GetPluginName() == name {
			matchedPluginNames = append(matchedPluginNames, plugin.GetPluginName())
			matches = append(matches, plugin)
		}
	}
	if len(matches) == 0 {
		return nil, fmt.Errorf("no volume plugin matched")
	}
	if len(matches) > 1 {
		return nil, fmt.Errorf("multiple volume plugins matched: %s", strings.Join(matchedPluginNames, ","))
	}
	return matches[0], nil
}
FindPluginByName fetches a plugin by name or by legacy name.  If no plugin
is found, returns error.
package volume
import (
	"fmt"
	"net"
	"strings"
	"sync"
	"github.com/golang/glog"
	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	"k8s.io/apimachinery/pkg/util/validation"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/kubernetes/pkg/cloudprovider"
	"k8s.io/kubernetes/pkg/util/io"
	"k8s.io/kubernetes/pkg/util/mount"
	"k8s.io/kubernetes/pkg/volume/util/recyclerclient"
)
const (
	VolumeParameterFSType = "fstype"
)
type VolumeOptions struct {
	PersistentVolumeReclaimPolicy v1.PersistentVolumeReclaimPolicy
	MountOptions []string
	PVName string
	PVC *v1.PersistentVolumeClaim
	ClusterName string
	CloudTags *map[string]string
	Parameters map[string]string
}
type DynamicPluginProber interface {
	Init() error
	Probe() (updated bool, probedPlugins []VolumePlugin, err error)
}
type VolumePlugin interface {
	Init(host VolumeHost) error
	GetPluginName() string
	GetVolumeName(spec *Spec) (string, error)
	CanSupport(spec *Spec) bool
	RequiresRemount() bool
	NewMounter(spec *Spec, podRef *v1.Pod, opts VolumeOptions) (Mounter, error)
	NewUnmounter(name string, podUID types.UID) (Unmounter, error)
	ConstructVolumeSpec(volumeName, mountPath string) (*Spec, error)
	SupportsMountOption() bool
	SupportsBulkVolumeVerification() bool
}
type PersistentVolumePlugin interface {
	VolumePlugin
	GetAccessModes() []v1.PersistentVolumeAccessMode
}
type RecyclableVolumePlugin interface {
	VolumePlugin
	Recycle(pvName string, spec *Spec, eventRecorder recyclerclient.RecycleEventRecorder) error
}
type DeletableVolumePlugin interface {
	VolumePlugin
	NewDeleter(spec *Spec) (Deleter, error)
}
const (
	ProvisionedVolumeName = "placeholder-for-provisioning"
)
type ProvisionableVolumePlugin interface {
	VolumePlugin
	NewProvisioner(options VolumeOptions) (Provisioner, error)
}
type AttachableVolumePlugin interface {
	VolumePlugin
	NewAttacher() (Attacher, error)
	NewDetacher() (Detacher, error)
	GetDeviceMountRefs(deviceMountPath string) ([]string, error)
}
type ExpandableVolumePlugin interface {
	VolumePlugin
	ExpandVolumeDevice(spec *Spec, newSize resource.Quantity, oldSize resource.Quantity) (resource.Quantity, error)
	RequiresFSResize() bool
}
type BlockVolumePlugin interface {
	VolumePlugin
	NewBlockVolumeMapper(spec *Spec, podRef *v1.Pod, opts VolumeOptions) (BlockVolumeMapper, error)
	NewBlockVolumeUnmapper(name string, podUID types.UID) (BlockVolumeUnmapper, error)
	ConstructBlockVolumeSpec(podUID types.UID, volumeName, mountPath string) (*Spec, error)
}
type VolumeHost interface {
	GetPluginDir(pluginName string) string
	GetVolumeDevicePluginDir(pluginName string) string
	GetPodVolumeDir(podUID types.UID, pluginName string, volumeName string) string
	GetPodPluginDir(podUID types.UID, pluginName string) string
	GetPodVolumeDeviceDir(podUID types.UID, pluginName string) string
	GetKubeClient() clientset.Interface
	NewWrapperMounter(volName string, spec Spec, pod *v1.Pod, opts VolumeOptions) (Mounter, error)
	NewWrapperUnmounter(volName string, spec Spec, podUID types.UID) (Unmounter, error)
	GetCloudProvider() cloudprovider.Interface
	GetMounter(pluginName string) mount.Interface
	GetWriter() io.Writer
	GetHostName() string
	GetHostIP() (net.IP, error)
	GetNodeAllocatable() (v1.ResourceList, error)
	GetSecretFunc() func(namespace, name string) (*v1.Secret, error)
	GetConfigMapFunc() func(namespace, name string) (*v1.ConfigMap, error)
	GetExec(pluginName string) mount.Exec
	GetNodeLabels() (map[string]string, error)
	GetNodeName() types.NodeName
}
type VolumePluginMgr struct {
	mutex         sync.Mutex
	plugins       map[string]VolumePlugin
	prober        DynamicPluginProber
	probedPlugins []VolumePlugin
	Host          VolumeHost
}
type Spec struct {
	Volume           *v1.Volume
	PersistentVolume *v1.PersistentVolume
	ReadOnly         bool
}
func (spec *Spec) Name() string {
	switch {
	case spec.Volume != nil:
		return spec.Volume.Name
	case spec.PersistentVolume != nil:
		return spec.PersistentVolume.Name
	default:
		return ""
	}
}
type VolumeConfig struct {
	RecyclerPodTemplate *v1.Pod
	RecyclerMinimumTimeout int
	RecyclerTimeoutIncrement int
	PVName string
	OtherAttributes map[string]string
	ProvisioningEnabled bool
}
func NewSpecFromVolume(vs *v1.Volume) *Spec {
	return &Spec{
		Volume: vs,
	}
}
func NewSpecFromPersistentVolume(pv *v1.PersistentVolume, readOnly bool) *Spec {
	return &Spec{
		PersistentVolume: pv,
		ReadOnly:         readOnly,
	}
}
func (pm *VolumePluginMgr) InitPlugins(plugins []VolumePlugin, prober DynamicPluginProber, host VolumeHost) error {
	pm.mutex.Lock()
	defer pm.mutex.Unlock()
	pm.Host = host
	if prober == nil {
		pm.prober = &dummyPluginProber{}
	} else {
		pm.prober = prober
	}
	if err := pm.prober.Init(); err != nil {
		glog.Errorf("Error initializing dynamic plugin prober: %s", err)
		pm.prober = &dummyPluginProber{}
	}
	if pm.plugins == nil {
		pm.plugins = map[string]VolumePlugin{}
	}
	allErrs := []error{}
	for _, plugin := range plugins {
		name := plugin.GetPluginName()
		if errs := validation.IsQualifiedName(name); len(errs) != 0 {
			allErrs = append(allErrs, fmt.Errorf("volume plugin has invalid name: %q: %s", name, strings.Join(errs, ";")))
			continue
		}
		if _, found := pm.plugins[name]; found {
			allErrs = append(allErrs, fmt.Errorf("volume plugin %q was registered more than once", name))
			continue
		}
		err := plugin.Init(host)
		if err != nil {
			glog.Errorf("Failed to load volume plugin %s, error: %s", name, err.Error())
			allErrs = append(allErrs, err)
			continue
		}
		pm.plugins[name] = plugin
		glog.V(1).Infof("Loaded volume plugin %q", name)
	}
	return utilerrors.NewAggregate(allErrs)
}
func (pm *VolumePluginMgr) initProbedPlugin(probedPlugin VolumePlugin) error {
	name := probedPlugin.GetPluginName()
	if errs := validation.IsQualifiedName(name); len(errs) != 0 {
		return fmt.Errorf("volume plugin has invalid name: %q: %s", name, strings.Join(errs, ";"))
	}
	err := probedPlugin.Init(pm.Host)
	if err != nil {
		return fmt.Errorf("Failed to load volume plugin %s, error: %s", name, err.Error())
	}
	glog.V(1).Infof("Loaded volume plugin %q", name)
	return nil
}
func (pm *VolumePluginMgr) FindPluginBySpec(spec *Spec) (VolumePlugin, error) {
	pm.mutex.Lock()
	defer pm.mutex.Unlock()
	if spec == nil {
		return nil, fmt.Errorf("Could not find plugin because volume spec is nil")
	}
	matchedPluginNames := []string{}
	matches := []VolumePlugin{}
	for k, v := range pm.plugins {
		if v.CanSupport(spec) {
			matchedPluginNames = append(matchedPluginNames, k)
			matches = append(matches, v)
		}
	}
	pm.refreshProbedPlugins()
	for _, plugin := range pm.probedPlugins {
		if plugin.CanSupport(spec) {
			matchedPluginNames = append(matchedPluginNames, plugin.GetPluginName())
			matches = append(matches, plugin)
		}
	}
	if len(matches) == 0 {
		return nil, fmt.Errorf("no volume plugin matched")
	}
	if len(matches) > 1 {
		return nil, fmt.Errorf("multiple volume plugins matched: %s", strings.Join(matchedPluginNames, ","))
	}
	return matches[0], nil
}