plugin.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. /*
  2. Copyright 2017 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package flexvolume
  14. import (
  15. "fmt"
  16. "path/filepath"
  17. "runtime"
  18. "strings"
  19. "sync"
  20. api "k8s.io/api/core/v1"
  21. "k8s.io/apimachinery/pkg/types"
  22. "k8s.io/klog"
  23. "k8s.io/kubernetes/pkg/util/mount"
  24. "k8s.io/kubernetes/pkg/volume"
  25. "k8s.io/kubernetes/pkg/volume/util"
  26. "k8s.io/utils/exec"
  27. utilstrings "k8s.io/utils/strings"
  28. )
  29. const (
  30. flexVolumePluginName = "kubernetes.io/flexvolume"
  31. flexVolumePluginNamePrefix = "flexvolume-"
  32. )
  33. // FlexVolumePlugin object.
  34. type flexVolumePlugin struct {
  35. driverName string
  36. execPath string
  37. host volume.VolumeHost
  38. runner exec.Interface
  39. sync.Mutex
  40. unsupportedCommands []string
  41. capabilities DriverCapabilities
  42. }
  43. type flexVolumeAttachablePlugin struct {
  44. *flexVolumePlugin
  45. }
  46. var _ volume.AttachableVolumePlugin = &flexVolumeAttachablePlugin{}
  47. var _ volume.PersistentVolumePlugin = &flexVolumePlugin{}
  48. var _ volume.NodeExpandableVolumePlugin = &flexVolumePlugin{}
  49. var _ volume.ExpandableVolumePlugin = &flexVolumePlugin{}
  50. var _ volume.DeviceMountableVolumePlugin = &flexVolumeAttachablePlugin{}
  51. // PluginFactory create flex volume plugin
  52. type PluginFactory interface {
  53. NewFlexVolumePlugin(pluginDir, driverName string, runner exec.Interface) (volume.VolumePlugin, error)
  54. }
  55. type pluginFactory struct{}
  56. func (pluginFactory) NewFlexVolumePlugin(pluginDir, name string, runner exec.Interface) (volume.VolumePlugin, error) {
  57. execPath := filepath.Join(pluginDir, name)
  58. driverName := utilstrings.UnescapeQualifiedName(name)
  59. flexPlugin := &flexVolumePlugin{
  60. driverName: driverName,
  61. execPath: execPath,
  62. runner: runner,
  63. unsupportedCommands: []string{},
  64. }
  65. // Initialize the plugin and probe the capabilities
  66. call := flexPlugin.NewDriverCall(initCmd)
  67. ds, err := call.Run()
  68. if err != nil {
  69. return nil, err
  70. }
  71. flexPlugin.capabilities = *ds.Capabilities
  72. if flexPlugin.capabilities.Attach {
  73. // Plugin supports attach/detach, so return flexVolumeAttachablePlugin
  74. return &flexVolumeAttachablePlugin{flexVolumePlugin: flexPlugin}, nil
  75. }
  76. return flexPlugin, nil
  77. }
  78. // Init is part of the volume.VolumePlugin interface.
  79. func (plugin *flexVolumePlugin) Init(host volume.VolumeHost) error {
  80. plugin.host = host
  81. // Hardwired 'success' as any errors from calling init() will be caught by NewFlexVolumePlugin()
  82. return nil
  83. }
  84. func (plugin *flexVolumePlugin) getExecutable() string {
  85. parts := strings.Split(plugin.driverName, "/")
  86. execName := parts[len(parts)-1]
  87. execPath := filepath.Join(plugin.execPath, execName)
  88. if runtime.GOOS == "windows" {
  89. execPath = util.GetWindowsPath(execPath)
  90. }
  91. return execPath
  92. }
  93. // Name is part of the volume.VolumePlugin interface.
  94. func (plugin *flexVolumePlugin) GetPluginName() string {
  95. return flexVolumePluginNamePrefix + plugin.driverName
  96. }
  97. // GetVolumeName is part of the volume.VolumePlugin interface.
  98. func (plugin *flexVolumePlugin) GetVolumeName(spec *volume.Spec) (string, error) {
  99. call := plugin.NewDriverCall(getVolumeNameCmd)
  100. call.AppendSpec(spec, plugin.host, nil)
  101. _, err := call.Run()
  102. if isCmdNotSupportedErr(err) {
  103. return (*pluginDefaults)(plugin).GetVolumeName(spec)
  104. } else if err != nil {
  105. return "", err
  106. }
  107. name, err := (*pluginDefaults)(plugin).GetVolumeName(spec)
  108. if err != nil {
  109. return "", err
  110. }
  111. klog.Warning(logPrefix(plugin), "GetVolumeName is not supported yet. Defaulting to PV or volume name: ", name)
  112. return name, nil
  113. }
  114. // CanSupport is part of the volume.VolumePlugin interface.
  115. func (plugin *flexVolumePlugin) CanSupport(spec *volume.Spec) bool {
  116. sourceDriver, err := getDriver(spec)
  117. if err != nil {
  118. return false
  119. }
  120. return sourceDriver == plugin.driverName
  121. }
  122. func (plugin *flexVolumePlugin) IsMigratedToCSI() bool {
  123. return false
  124. }
  125. // RequiresRemount is part of the volume.VolumePlugin interface.
  126. func (plugin *flexVolumePlugin) RequiresRemount() bool {
  127. return false
  128. }
  129. // GetAccessModes gets the allowed access modes for this plugin.
  130. func (plugin *flexVolumePlugin) GetAccessModes() []api.PersistentVolumeAccessMode {
  131. return []api.PersistentVolumeAccessMode{
  132. api.ReadWriteOnce,
  133. api.ReadOnlyMany,
  134. }
  135. }
  136. // NewMounter is part of the volume.VolumePlugin interface.
  137. func (plugin *flexVolumePlugin) NewMounter(spec *volume.Spec, pod *api.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
  138. return plugin.newMounterInternal(spec, pod, plugin.host.GetMounter(plugin.GetPluginName()), plugin.runner)
  139. }
  140. // newMounterInternal is the internal mounter routine to build the volume.
  141. func (plugin *flexVolumePlugin) newMounterInternal(spec *volume.Spec, pod *api.Pod, mounter mount.Interface, runner exec.Interface) (volume.Mounter, error) {
  142. sourceDriver, err := getDriver(spec)
  143. if err != nil {
  144. return nil, err
  145. }
  146. readOnly, err := getReadOnly(spec)
  147. if err != nil {
  148. return nil, err
  149. }
  150. var metricsProvider volume.MetricsProvider
  151. if plugin.capabilities.SupportsMetrics {
  152. metricsProvider = volume.NewMetricsStatFS(plugin.host.GetPodVolumeDir(
  153. pod.UID, utilstrings.EscapeQualifiedName(sourceDriver), spec.Name()))
  154. } else {
  155. metricsProvider = &volume.MetricsNil{}
  156. }
  157. return &flexVolumeMounter{
  158. flexVolume: &flexVolume{
  159. driverName: sourceDriver,
  160. execPath: plugin.getExecutable(),
  161. mounter: mounter,
  162. plugin: plugin,
  163. podName: pod.Name,
  164. podUID: pod.UID,
  165. podNamespace: pod.Namespace,
  166. podServiceAccountName: pod.Spec.ServiceAccountName,
  167. volName: spec.Name(),
  168. MetricsProvider: metricsProvider,
  169. },
  170. runner: runner,
  171. spec: spec,
  172. readOnly: readOnly,
  173. }, nil
  174. }
  175. // NewUnmounter is part of the volume.VolumePlugin interface.
  176. func (plugin *flexVolumePlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
  177. return plugin.newUnmounterInternal(volName, podUID, plugin.host.GetMounter(plugin.GetPluginName()), plugin.runner)
  178. }
  179. // newUnmounterInternal is the internal unmounter routine to clean the volume.
  180. func (plugin *flexVolumePlugin) newUnmounterInternal(volName string, podUID types.UID, mounter mount.Interface, runner exec.Interface) (volume.Unmounter, error) {
  181. var metricsProvider volume.MetricsProvider
  182. if plugin.capabilities.SupportsMetrics {
  183. metricsProvider = volume.NewMetricsStatFS(plugin.host.GetPodVolumeDir(
  184. podUID, utilstrings.EscapeQualifiedName(plugin.driverName), volName))
  185. } else {
  186. metricsProvider = &volume.MetricsNil{}
  187. }
  188. return &flexVolumeUnmounter{
  189. flexVolume: &flexVolume{
  190. driverName: plugin.driverName,
  191. execPath: plugin.getExecutable(),
  192. mounter: mounter,
  193. plugin: plugin,
  194. podUID: podUID,
  195. volName: volName,
  196. MetricsProvider: metricsProvider,
  197. },
  198. runner: runner,
  199. }, nil
  200. }
  201. // NewAttacher is part of the volume.AttachableVolumePlugin interface.
  202. func (plugin *flexVolumeAttachablePlugin) NewAttacher() (volume.Attacher, error) {
  203. return &flexVolumeAttacher{plugin}, nil
  204. }
  205. func (plugin *flexVolumeAttachablePlugin) NewDeviceMounter() (volume.DeviceMounter, error) {
  206. return plugin.NewAttacher()
  207. }
  208. // NewDetacher is part of the volume.AttachableVolumePlugin interface.
  209. func (plugin *flexVolumeAttachablePlugin) NewDetacher() (volume.Detacher, error) {
  210. return &flexVolumeDetacher{plugin}, nil
  211. }
  212. func (plugin *flexVolumeAttachablePlugin) NewDeviceUnmounter() (volume.DeviceUnmounter, error) {
  213. return plugin.NewDetacher()
  214. }
  215. func (plugin *flexVolumeAttachablePlugin) CanAttach(spec *volume.Spec) (bool, error) {
  216. return true, nil
  217. }
  218. func (plugin *flexVolumeAttachablePlugin) CanDeviceMount(spec *volume.Spec) (bool, error) {
  219. return true, nil
  220. }
  221. // ConstructVolumeSpec is part of the volume.AttachableVolumePlugin interface.
  222. func (plugin *flexVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) {
  223. flexVolume := &api.Volume{
  224. Name: volumeName,
  225. VolumeSource: api.VolumeSource{
  226. FlexVolume: &api.FlexVolumeSource{
  227. Driver: plugin.driverName,
  228. },
  229. },
  230. }
  231. return volume.NewSpecFromVolume(flexVolume), nil
  232. }
  233. func (plugin *flexVolumePlugin) SupportsMountOption() bool {
  234. return false
  235. }
  236. // Mark the given commands as unsupported.
  237. func (plugin *flexVolumePlugin) unsupported(commands ...string) {
  238. plugin.Lock()
  239. defer plugin.Unlock()
  240. plugin.unsupportedCommands = append(plugin.unsupportedCommands, commands...)
  241. }
  242. func (plugin *flexVolumePlugin) SupportsBulkVolumeVerification() bool {
  243. return false
  244. }
  245. // Returns true iff the given command is known to be unsupported.
  246. func (plugin *flexVolumePlugin) isUnsupported(command string) bool {
  247. plugin.Lock()
  248. defer plugin.Unlock()
  249. for _, unsupportedCommand := range plugin.unsupportedCommands {
  250. if command == unsupportedCommand {
  251. return true
  252. }
  253. }
  254. return false
  255. }
  256. func (plugin *flexVolumePlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) {
  257. mounter := plugin.host.GetMounter(plugin.GetPluginName())
  258. return mounter.GetMountRefs(deviceMountPath)
  259. }
  260. func (plugin *flexVolumePlugin) getDeviceMountPath(spec *volume.Spec) (string, error) {
  261. volumeName, err := plugin.GetVolumeName(spec)
  262. if err != nil {
  263. return "", fmt.Errorf("GetVolumeName failed from getDeviceMountPath: %s", err)
  264. }
  265. mountsDir := filepath.Join(plugin.host.GetPluginDir(flexVolumePluginName), plugin.driverName, "mounts")
  266. return filepath.Join(mountsDir, volumeName), nil
  267. }
  268. func (plugin *flexVolumePlugin) RequiresFSResize() bool {
  269. return plugin.capabilities.RequiresFSResize
  270. }