attacher.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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 rbd
  14. import (
  15. "fmt"
  16. "os"
  17. "time"
  18. "k8s.io/api/core/v1"
  19. "k8s.io/apimachinery/pkg/types"
  20. "k8s.io/klog"
  21. "k8s.io/kubernetes/pkg/util/mount"
  22. "k8s.io/kubernetes/pkg/volume"
  23. volutil "k8s.io/kubernetes/pkg/volume/util"
  24. )
  25. // NewAttacher implements AttachableVolumePlugin.NewAttacher.
  26. func (plugin *rbdPlugin) NewAttacher() (volume.Attacher, error) {
  27. return plugin.newAttacherInternal(&RBDUtil{})
  28. }
  29. // NewDeviceMounter implements DeviceMountableVolumePlugin.NewDeviceMounter
  30. func (plugin *rbdPlugin) NewDeviceMounter() (volume.DeviceMounter, error) {
  31. return plugin.NewAttacher()
  32. }
  33. func (plugin *rbdPlugin) newAttacherInternal(manager diskManager) (volume.Attacher, error) {
  34. return &rbdAttacher{
  35. plugin: plugin,
  36. manager: manager,
  37. mounter: volutil.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host),
  38. }, nil
  39. }
  40. // NewDetacher implements AttachableVolumePlugin.NewDetacher.
  41. func (plugin *rbdPlugin) NewDetacher() (volume.Detacher, error) {
  42. return plugin.newDetacherInternal(&RBDUtil{})
  43. }
  44. // NewDeviceUnmounter implements DeviceMountableVolumePlugin.NewDeviceUnmounter
  45. func (plugin *rbdPlugin) NewDeviceUnmounter() (volume.DeviceUnmounter, error) {
  46. return plugin.NewDetacher()
  47. }
  48. func (plugin *rbdPlugin) newDetacherInternal(manager diskManager) (volume.Detacher, error) {
  49. return &rbdDetacher{
  50. plugin: plugin,
  51. manager: manager,
  52. mounter: volutil.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host),
  53. }, nil
  54. }
  55. // GetDeviceMountRefs implements AttachableVolumePlugin.GetDeviceMountRefs.
  56. func (plugin *rbdPlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) {
  57. mounter := plugin.host.GetMounter(plugin.GetPluginName())
  58. return mounter.GetMountRefs(deviceMountPath)
  59. }
  60. func (plugin *rbdPlugin) CanAttach(spec *volume.Spec) (bool, error) {
  61. return true, nil
  62. }
  63. func (plugin *rbdPlugin) CanDeviceMount(spec *volume.Spec) (bool, error) {
  64. return true, nil
  65. }
  66. // rbdAttacher implements volume.Attacher interface.
  67. type rbdAttacher struct {
  68. plugin *rbdPlugin
  69. mounter *mount.SafeFormatAndMount
  70. manager diskManager
  71. }
  72. var _ volume.Attacher = &rbdAttacher{}
  73. var _ volume.DeviceMounter = &rbdAttacher{}
  74. // Attach implements Attacher.Attach.
  75. // We do not lock image here, because it requires kube-controller-manager to
  76. // access external `rbd` utility. And there is no need since AttachDetach
  77. // controller will not try to attach RWO volumes which are already attached to
  78. // other nodes.
  79. func (attacher *rbdAttacher) Attach(spec *volume.Spec, nodeName types.NodeName) (string, error) {
  80. return "", nil
  81. }
  82. // VolumesAreAttached implements Attacher.VolumesAreAttached.
  83. // There is no way to confirm whether the volume is attached or not from
  84. // outside of the kubelet node. This method needs to return true always, like
  85. // iSCSI, FC plugin.
  86. func (attacher *rbdAttacher) VolumesAreAttached(specs []*volume.Spec, nodeName types.NodeName) (map[*volume.Spec]bool, error) {
  87. volumesAttachedCheck := make(map[*volume.Spec]bool)
  88. for _, spec := range specs {
  89. volumesAttachedCheck[spec] = true
  90. }
  91. return volumesAttachedCheck, nil
  92. }
  93. // WaitForAttach implements Attacher.WaitForAttach. It's called by kubelet to
  94. // attach volume onto the node.
  95. // This method is idempotent, callers are responsible for retrying on failure.
  96. func (attacher *rbdAttacher) WaitForAttach(spec *volume.Spec, devicePath string, pod *v1.Pod, timeout time.Duration) (string, error) {
  97. klog.V(4).Infof("rbd: waiting for attach volume (name: %s) for pod (name: %s, uid: %s)", spec.Name(), pod.Name, pod.UID)
  98. mounter, err := attacher.plugin.createMounterFromVolumeSpecAndPod(spec, pod)
  99. if err != nil {
  100. klog.Warningf("failed to create mounter: %v", spec)
  101. return "", err
  102. }
  103. realDevicePath, err := attacher.manager.AttachDisk(*mounter)
  104. if err != nil {
  105. return "", err
  106. }
  107. klog.V(3).Infof("rbd: successfully wait for attach volume (spec: %s, pool: %s, image: %s) at %s", spec.Name(), mounter.Pool, mounter.Image, realDevicePath)
  108. return realDevicePath, nil
  109. }
  110. // GetDeviceMountPath implements Attacher.GetDeviceMountPath.
  111. func (attacher *rbdAttacher) GetDeviceMountPath(spec *volume.Spec) (string, error) {
  112. img, err := getVolumeSourceImage(spec)
  113. if err != nil {
  114. return "", err
  115. }
  116. pool, err := getVolumeSourcePool(spec)
  117. if err != nil {
  118. return "", err
  119. }
  120. return makePDNameInternal(attacher.plugin.host, pool, img), nil
  121. }
  122. // MountDevice implements Attacher.MountDevice. It is called by the kubelet to
  123. // mount device at the given mount path.
  124. // This method is idempotent, callers are responsible for retrying on failure.
  125. func (attacher *rbdAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error {
  126. klog.V(4).Infof("rbd: mouting device %s to %s", devicePath, deviceMountPath)
  127. notMnt, err := attacher.mounter.IsLikelyNotMountPoint(deviceMountPath)
  128. if err != nil {
  129. if os.IsNotExist(err) {
  130. if err := os.MkdirAll(deviceMountPath, 0750); err != nil {
  131. return err
  132. }
  133. notMnt = true
  134. } else {
  135. return err
  136. }
  137. }
  138. if !notMnt {
  139. return nil
  140. }
  141. fstype, err := getVolumeSourceFSType(spec)
  142. if err != nil {
  143. return err
  144. }
  145. ro, err := getVolumeSourceReadOnly(spec)
  146. if err != nil {
  147. return err
  148. }
  149. options := []string{}
  150. if ro {
  151. options = append(options, "ro")
  152. }
  153. mountOptions := volutil.MountOptionFromSpec(spec, options...)
  154. err = attacher.mounter.FormatAndMount(devicePath, deviceMountPath, fstype, mountOptions)
  155. if err != nil {
  156. os.Remove(deviceMountPath)
  157. return fmt.Errorf("rbd: failed to mount device %s at %s (fstype: %s), error %v", devicePath, deviceMountPath, fstype, err)
  158. }
  159. klog.V(3).Infof("rbd: successfully mount device %s at %s (fstype: %s)", devicePath, deviceMountPath, fstype)
  160. return nil
  161. }
  162. // rbdDetacher implements volume.Detacher interface.
  163. type rbdDetacher struct {
  164. plugin *rbdPlugin
  165. manager diskManager
  166. mounter *mount.SafeFormatAndMount
  167. }
  168. var _ volume.Detacher = &rbdDetacher{}
  169. var _ volume.DeviceUnmounter = &rbdDetacher{}
  170. // UnmountDevice implements Detacher.UnmountDevice. It unmounts the global
  171. // mount of the RBD image. This is called once all bind mounts have been
  172. // unmounted.
  173. // Internally, it does four things:
  174. // - Unmount device from deviceMountPath.
  175. // - Detach device from the node.
  176. // - Remove lock if found. (No need to check volume readonly or not, because
  177. // device is not on the node anymore, it's safe to remove lock.)
  178. // - Remove the deviceMountPath at last.
  179. // This method is idempotent, callers are responsible for retrying on failure.
  180. func (detacher *rbdDetacher) UnmountDevice(deviceMountPath string) error {
  181. if pathExists, pathErr := mount.PathExists(deviceMountPath); pathErr != nil {
  182. return fmt.Errorf("Error checking if path exists: %v", pathErr)
  183. } else if !pathExists {
  184. klog.Warningf("Warning: Unmount skipped because path does not exist: %v", deviceMountPath)
  185. return nil
  186. }
  187. devicePath, _, err := mount.GetDeviceNameFromMount(detacher.mounter, deviceMountPath)
  188. if err != nil {
  189. return err
  190. }
  191. // Unmount the device from the device mount point.
  192. klog.V(4).Infof("rbd: unmouting device mountpoint %s", deviceMountPath)
  193. if err = detacher.mounter.Unmount(deviceMountPath); err != nil {
  194. return err
  195. }
  196. klog.V(3).Infof("rbd: successfully umount device mountpath %s", deviceMountPath)
  197. klog.V(4).Infof("rbd: detaching device %s", devicePath)
  198. err = detacher.manager.DetachDisk(detacher.plugin, deviceMountPath, devicePath)
  199. if err != nil {
  200. return err
  201. }
  202. klog.V(3).Infof("rbd: successfully detach device %s", devicePath)
  203. err = os.Remove(deviceMountPath)
  204. if err != nil {
  205. return err
  206. }
  207. klog.V(3).Infof("rbd: successfully remove device mount point %s", deviceMountPath)
  208. return nil
  209. }
  210. // Detach implements Detacher.Detach.
  211. func (detacher *rbdDetacher) Detach(volumeName string, nodeName types.NodeName) error {
  212. return nil
  213. }