func (pm *VolumePluginMgr) FindExpandablePluginBySpec(spec *Spec) (ExpandableVolumePlugin, error) {
	volumePlugin, err := pm.FindPluginBySpec(spec)
	if err != nil {
		return nil, err
	}
	if expandableVolumePlugin, ok := volumePlugin.(ExpandableVolumePlugin); ok {
		return expandableVolumePlugin, nil
	}
	return nil, nil
}
FindExpandablePluginBySpec fetches a persistent volume plugin by spec.
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
}
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
}
func (pm *VolumePluginMgr) refreshProbedPlugins() {
	updated, plugins, err := pm.prober.Probe()
	if err != nil {
		glog.Errorf("Error dynamically probing plugins: %s", err)
		return  
	}
	if updated {
		pm.probedPlugins = []VolumePlugin{}
		for _, plugin := range plugins {
			if err := pm.initProbedPlugin(plugin); err != nil {
				glog.Errorf("Error initializing dynamically probed plugin %s; error: %s",
					plugin.GetPluginName(), err)
				continue
			}
			pm.probedPlugins = append(pm.probedPlugins, plugin)
		}
	}
}
func (pm *VolumePluginMgr) FindPersistentPluginBySpec(spec *Spec) (PersistentVolumePlugin, error) {
	volumePlugin, err := pm.FindPluginBySpec(spec)
	if err != nil {
		return nil, fmt.Errorf("Could not find volume plugin for spec: %#v", spec)
	}
	if persistentVolumePlugin, ok := volumePlugin.(PersistentVolumePlugin); ok {
		return persistentVolumePlugin, nil
	}
	return nil, fmt.Errorf("no persistent volume plugin matched")
}
func (pm *VolumePluginMgr) FindPersistentPluginByName(name string) (PersistentVolumePlugin, error) {
	volumePlugin, err := pm.FindPluginByName(name)
	if err != nil {
		return nil, err
	}
	if persistentVolumePlugin, ok := volumePlugin.(PersistentVolumePlugin); ok {
		return persistentVolumePlugin, nil
	}
	return nil, fmt.Errorf("no persistent volume plugin matched")
}
func (pm *VolumePluginMgr) FindRecyclablePluginBySpec(spec *Spec) (RecyclableVolumePlugin, error) {
	volumePlugin, err := pm.FindPluginBySpec(spec)
	if err != nil {
		return nil, err
	}
	if recyclableVolumePlugin, ok := volumePlugin.(RecyclableVolumePlugin); ok {
		return recyclableVolumePlugin, nil
	}
	return nil, fmt.Errorf("no recyclable volume plugin matched")
}
func (pm *VolumePluginMgr) FindProvisionablePluginByName(name string) (ProvisionableVolumePlugin, error) {
	volumePlugin, err := pm.FindPluginByName(name)
	if err != nil {
		return nil, err
	}
	if provisionableVolumePlugin, ok := volumePlugin.(ProvisionableVolumePlugin); ok {
		return provisionableVolumePlugin, nil
	}
	return nil, fmt.Errorf("no provisionable volume plugin matched")
}
func (pm *VolumePluginMgr) FindDeletablePluginBySpec(spec *Spec) (DeletableVolumePlugin, error) {
	volumePlugin, err := pm.FindPluginBySpec(spec)
	if err != nil {
		return nil, err
	}
	if deletableVolumePlugin, ok := volumePlugin.(DeletableVolumePlugin); ok {
		return deletableVolumePlugin, nil
	}
	return nil, fmt.Errorf("no deletable volume plugin matched")
}
func (pm *VolumePluginMgr) FindDeletablePluginByName(name string) (DeletableVolumePlugin, error) {
	volumePlugin, err := pm.FindPluginByName(name)
	if err != nil {
		return nil, err
	}
	if deletableVolumePlugin, ok := volumePlugin.(DeletableVolumePlugin); ok {
		return deletableVolumePlugin, nil
	}
	return nil, fmt.Errorf("no deletable volume plugin matched")
}
func (pm *VolumePluginMgr) FindCreatablePluginBySpec(spec *Spec) (ProvisionableVolumePlugin, error) {
	volumePlugin, err := pm.FindPluginBySpec(spec)
	if err != nil {
		return nil, err
	}
	if provisionableVolumePlugin, ok := volumePlugin.(ProvisionableVolumePlugin); ok {
		return provisionableVolumePlugin, nil
	}
	return nil, fmt.Errorf("no creatable volume plugin matched")
}
func (pm *VolumePluginMgr) FindAttachablePluginBySpec(spec *Spec) (AttachableVolumePlugin, error) {
	volumePlugin, err := pm.FindPluginBySpec(spec)
	if err != nil {
		return nil, err
	}
	if attachableVolumePlugin, ok := volumePlugin.(AttachableVolumePlugin); ok {
		return attachableVolumePlugin, nil
	}
	return nil, nil
}
func (pm *VolumePluginMgr) FindAttachablePluginByName(name string) (AttachableVolumePlugin, error) {
	volumePlugin, err := pm.FindPluginByName(name)
	if err != nil {
		return nil, err
	}
	if attachablePlugin, ok := volumePlugin.(AttachableVolumePlugin); ok {
		return attachablePlugin, nil
	}
	return nil, nil
}