123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- /*
- Copyright 2017 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package flexvolume
- import (
- "fmt"
- "path/filepath"
- "runtime"
- "strings"
- "sync"
- api "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/types"
- "k8s.io/klog"
- "k8s.io/kubernetes/pkg/util/mount"
- "k8s.io/kubernetes/pkg/volume"
- "k8s.io/kubernetes/pkg/volume/util"
- "k8s.io/utils/exec"
- utilstrings "k8s.io/utils/strings"
- )
- const (
- flexVolumePluginName = "kubernetes.io/flexvolume"
- flexVolumePluginNamePrefix = "flexvolume-"
- )
- // FlexVolumePlugin object.
- type flexVolumePlugin struct {
- driverName string
- execPath string
- host volume.VolumeHost
- runner exec.Interface
- sync.Mutex
- unsupportedCommands []string
- capabilities DriverCapabilities
- }
- type flexVolumeAttachablePlugin struct {
- *flexVolumePlugin
- }
- var _ volume.AttachableVolumePlugin = &flexVolumeAttachablePlugin{}
- var _ volume.PersistentVolumePlugin = &flexVolumePlugin{}
- var _ volume.NodeExpandableVolumePlugin = &flexVolumePlugin{}
- var _ volume.ExpandableVolumePlugin = &flexVolumePlugin{}
- var _ volume.DeviceMountableVolumePlugin = &flexVolumeAttachablePlugin{}
- // PluginFactory create flex volume plugin
- type PluginFactory interface {
- NewFlexVolumePlugin(pluginDir, driverName string, runner exec.Interface) (volume.VolumePlugin, error)
- }
- type pluginFactory struct{}
- func (pluginFactory) NewFlexVolumePlugin(pluginDir, name string, runner exec.Interface) (volume.VolumePlugin, error) {
- execPath := filepath.Join(pluginDir, name)
- driverName := utilstrings.UnescapeQualifiedName(name)
- flexPlugin := &flexVolumePlugin{
- driverName: driverName,
- execPath: execPath,
- runner: runner,
- unsupportedCommands: []string{},
- }
- // Initialize the plugin and probe the capabilities
- call := flexPlugin.NewDriverCall(initCmd)
- ds, err := call.Run()
- if err != nil {
- return nil, err
- }
- flexPlugin.capabilities = *ds.Capabilities
- if flexPlugin.capabilities.Attach {
- // Plugin supports attach/detach, so return flexVolumeAttachablePlugin
- return &flexVolumeAttachablePlugin{flexVolumePlugin: flexPlugin}, nil
- }
- return flexPlugin, nil
- }
- // Init is part of the volume.VolumePlugin interface.
- func (plugin *flexVolumePlugin) Init(host volume.VolumeHost) error {
- plugin.host = host
- // Hardwired 'success' as any errors from calling init() will be caught by NewFlexVolumePlugin()
- return nil
- }
- func (plugin *flexVolumePlugin) getExecutable() string {
- parts := strings.Split(plugin.driverName, "/")
- execName := parts[len(parts)-1]
- execPath := filepath.Join(plugin.execPath, execName)
- if runtime.GOOS == "windows" {
- execPath = util.GetWindowsPath(execPath)
- }
- return execPath
- }
- // Name is part of the volume.VolumePlugin interface.
- func (plugin *flexVolumePlugin) GetPluginName() string {
- return flexVolumePluginNamePrefix + plugin.driverName
- }
- // GetVolumeName is part of the volume.VolumePlugin interface.
- func (plugin *flexVolumePlugin) GetVolumeName(spec *volume.Spec) (string, error) {
- call := plugin.NewDriverCall(getVolumeNameCmd)
- call.AppendSpec(spec, plugin.host, nil)
- _, err := call.Run()
- if isCmdNotSupportedErr(err) {
- return (*pluginDefaults)(plugin).GetVolumeName(spec)
- } else if err != nil {
- return "", err
- }
- name, err := (*pluginDefaults)(plugin).GetVolumeName(spec)
- if err != nil {
- return "", err
- }
- klog.Warning(logPrefix(plugin), "GetVolumeName is not supported yet. Defaulting to PV or volume name: ", name)
- return name, nil
- }
- // CanSupport is part of the volume.VolumePlugin interface.
- func (plugin *flexVolumePlugin) CanSupport(spec *volume.Spec) bool {
- sourceDriver, err := getDriver(spec)
- if err != nil {
- return false
- }
- return sourceDriver == plugin.driverName
- }
- func (plugin *flexVolumePlugin) IsMigratedToCSI() bool {
- return false
- }
- // RequiresRemount is part of the volume.VolumePlugin interface.
- func (plugin *flexVolumePlugin) RequiresRemount() bool {
- return false
- }
- // GetAccessModes gets the allowed access modes for this plugin.
- func (plugin *flexVolumePlugin) GetAccessModes() []api.PersistentVolumeAccessMode {
- return []api.PersistentVolumeAccessMode{
- api.ReadWriteOnce,
- api.ReadOnlyMany,
- }
- }
- // NewMounter is part of the volume.VolumePlugin interface.
- func (plugin *flexVolumePlugin) NewMounter(spec *volume.Spec, pod *api.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
- return plugin.newMounterInternal(spec, pod, plugin.host.GetMounter(plugin.GetPluginName()), plugin.runner)
- }
- // newMounterInternal is the internal mounter routine to build the volume.
- func (plugin *flexVolumePlugin) newMounterInternal(spec *volume.Spec, pod *api.Pod, mounter mount.Interface, runner exec.Interface) (volume.Mounter, error) {
- sourceDriver, err := getDriver(spec)
- if err != nil {
- return nil, err
- }
- readOnly, err := getReadOnly(spec)
- if err != nil {
- return nil, err
- }
- var metricsProvider volume.MetricsProvider
- if plugin.capabilities.SupportsMetrics {
- metricsProvider = volume.NewMetricsStatFS(plugin.host.GetPodVolumeDir(
- pod.UID, utilstrings.EscapeQualifiedName(sourceDriver), spec.Name()))
- } else {
- metricsProvider = &volume.MetricsNil{}
- }
- return &flexVolumeMounter{
- flexVolume: &flexVolume{
- driverName: sourceDriver,
- execPath: plugin.getExecutable(),
- mounter: mounter,
- plugin: plugin,
- podName: pod.Name,
- podUID: pod.UID,
- podNamespace: pod.Namespace,
- podServiceAccountName: pod.Spec.ServiceAccountName,
- volName: spec.Name(),
- MetricsProvider: metricsProvider,
- },
- runner: runner,
- spec: spec,
- readOnly: readOnly,
- }, nil
- }
- // NewUnmounter is part of the volume.VolumePlugin interface.
- func (plugin *flexVolumePlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
- return plugin.newUnmounterInternal(volName, podUID, plugin.host.GetMounter(plugin.GetPluginName()), plugin.runner)
- }
- // newUnmounterInternal is the internal unmounter routine to clean the volume.
- func (plugin *flexVolumePlugin) newUnmounterInternal(volName string, podUID types.UID, mounter mount.Interface, runner exec.Interface) (volume.Unmounter, error) {
- var metricsProvider volume.MetricsProvider
- if plugin.capabilities.SupportsMetrics {
- metricsProvider = volume.NewMetricsStatFS(plugin.host.GetPodVolumeDir(
- podUID, utilstrings.EscapeQualifiedName(plugin.driverName), volName))
- } else {
- metricsProvider = &volume.MetricsNil{}
- }
- return &flexVolumeUnmounter{
- flexVolume: &flexVolume{
- driverName: plugin.driverName,
- execPath: plugin.getExecutable(),
- mounter: mounter,
- plugin: plugin,
- podUID: podUID,
- volName: volName,
- MetricsProvider: metricsProvider,
- },
- runner: runner,
- }, nil
- }
- // NewAttacher is part of the volume.AttachableVolumePlugin interface.
- func (plugin *flexVolumeAttachablePlugin) NewAttacher() (volume.Attacher, error) {
- return &flexVolumeAttacher{plugin}, nil
- }
- func (plugin *flexVolumeAttachablePlugin) NewDeviceMounter() (volume.DeviceMounter, error) {
- return plugin.NewAttacher()
- }
- // NewDetacher is part of the volume.AttachableVolumePlugin interface.
- func (plugin *flexVolumeAttachablePlugin) NewDetacher() (volume.Detacher, error) {
- return &flexVolumeDetacher{plugin}, nil
- }
- func (plugin *flexVolumeAttachablePlugin) NewDeviceUnmounter() (volume.DeviceUnmounter, error) {
- return plugin.NewDetacher()
- }
- func (plugin *flexVolumeAttachablePlugin) CanAttach(spec *volume.Spec) (bool, error) {
- return true, nil
- }
- func (plugin *flexVolumeAttachablePlugin) CanDeviceMount(spec *volume.Spec) (bool, error) {
- return true, nil
- }
- // ConstructVolumeSpec is part of the volume.AttachableVolumePlugin interface.
- func (plugin *flexVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) {
- flexVolume := &api.Volume{
- Name: volumeName,
- VolumeSource: api.VolumeSource{
- FlexVolume: &api.FlexVolumeSource{
- Driver: plugin.driverName,
- },
- },
- }
- return volume.NewSpecFromVolume(flexVolume), nil
- }
- func (plugin *flexVolumePlugin) SupportsMountOption() bool {
- return false
- }
- // Mark the given commands as unsupported.
- func (plugin *flexVolumePlugin) unsupported(commands ...string) {
- plugin.Lock()
- defer plugin.Unlock()
- plugin.unsupportedCommands = append(plugin.unsupportedCommands, commands...)
- }
- func (plugin *flexVolumePlugin) SupportsBulkVolumeVerification() bool {
- return false
- }
- // Returns true iff the given command is known to be unsupported.
- func (plugin *flexVolumePlugin) isUnsupported(command string) bool {
- plugin.Lock()
- defer plugin.Unlock()
- for _, unsupportedCommand := range plugin.unsupportedCommands {
- if command == unsupportedCommand {
- return true
- }
- }
- return false
- }
- func (plugin *flexVolumePlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) {
- mounter := plugin.host.GetMounter(plugin.GetPluginName())
- return mounter.GetMountRefs(deviceMountPath)
- }
- func (plugin *flexVolumePlugin) getDeviceMountPath(spec *volume.Spec) (string, error) {
- volumeName, err := plugin.GetVolumeName(spec)
- if err != nil {
- return "", fmt.Errorf("GetVolumeName failed from getDeviceMountPath: %s", err)
- }
- mountsDir := filepath.Join(plugin.host.GetPluginDir(flexVolumePluginName), plugin.driverName, "mounts")
- return filepath.Join(mountsDir, volumeName), nil
- }
- func (plugin *flexVolumePlugin) RequiresFSResize() bool {
- return plugin.capabilities.RequiresFSResize
- }
|