attacher.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  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 iscsi
  14. import (
  15. "fmt"
  16. "os"
  17. "time"
  18. "k8s.io/klog"
  19. "k8s.io/utils/keymutex"
  20. "k8s.io/utils/mount"
  21. v1 "k8s.io/api/core/v1"
  22. "k8s.io/apimachinery/pkg/types"
  23. utilfeature "k8s.io/apiserver/pkg/util/feature"
  24. "k8s.io/kubernetes/pkg/features"
  25. "k8s.io/kubernetes/pkg/volume"
  26. volumeutil "k8s.io/kubernetes/pkg/volume/util"
  27. )
  28. type iscsiAttacher struct {
  29. host volume.VolumeHost
  30. targetLocks keymutex.KeyMutex
  31. manager diskManager
  32. }
  33. var _ volume.Attacher = &iscsiAttacher{}
  34. var _ volume.DeviceMounter = &iscsiAttacher{}
  35. var _ volume.AttachableVolumePlugin = &iscsiPlugin{}
  36. var _ volume.DeviceMountableVolumePlugin = &iscsiPlugin{}
  37. func (plugin *iscsiPlugin) NewAttacher() (volume.Attacher, error) {
  38. return &iscsiAttacher{
  39. host: plugin.host,
  40. targetLocks: plugin.targetLocks,
  41. manager: &ISCSIUtil{},
  42. }, nil
  43. }
  44. func (plugin *iscsiPlugin) NewDeviceMounter() (volume.DeviceMounter, error) {
  45. return plugin.NewAttacher()
  46. }
  47. func (plugin *iscsiPlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) {
  48. mounter := plugin.host.GetMounter(iscsiPluginName)
  49. return mounter.GetMountRefs(deviceMountPath)
  50. }
  51. func (attacher *iscsiAttacher) Attach(spec *volume.Spec, nodeName types.NodeName) (string, error) {
  52. return "", nil
  53. }
  54. func (attacher *iscsiAttacher) VolumesAreAttached(specs []*volume.Spec, nodeName types.NodeName) (map[*volume.Spec]bool, error) {
  55. volumesAttachedCheck := make(map[*volume.Spec]bool)
  56. for _, spec := range specs {
  57. volumesAttachedCheck[spec] = true
  58. }
  59. return volumesAttachedCheck, nil
  60. }
  61. func (attacher *iscsiAttacher) WaitForAttach(spec *volume.Spec, devicePath string, pod *v1.Pod, timeout time.Duration) (string, error) {
  62. mounter, err := volumeSpecToMounter(spec, attacher.host, attacher.targetLocks, pod)
  63. if err != nil {
  64. klog.Warningf("failed to get iscsi mounter: %v", err)
  65. return "", err
  66. }
  67. return attacher.manager.AttachDisk(*mounter)
  68. }
  69. func (attacher *iscsiAttacher) GetDeviceMountPath(
  70. spec *volume.Spec) (string, error) {
  71. mounter, err := volumeSpecToMounter(spec, attacher.host, attacher.targetLocks, nil)
  72. if err != nil {
  73. klog.Warningf("failed to get iscsi mounter: %v", err)
  74. return "", err
  75. }
  76. if mounter.InitiatorName != "" {
  77. // new iface name is <target portal>:<volume name>
  78. mounter.Iface = mounter.Portals[0] + ":" + mounter.VolName
  79. }
  80. return attacher.manager.MakeGlobalPDName(*mounter.iscsiDisk), nil
  81. }
  82. func (attacher *iscsiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error {
  83. mounter := attacher.host.GetMounter(iscsiPluginName)
  84. notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath)
  85. if err != nil {
  86. if os.IsNotExist(err) {
  87. if err := os.MkdirAll(deviceMountPath, 0750); err != nil {
  88. return err
  89. }
  90. notMnt = true
  91. } else {
  92. return err
  93. }
  94. }
  95. readOnly, fsType, err := getISCSIVolumeInfo(spec)
  96. if err != nil {
  97. return err
  98. }
  99. options := []string{}
  100. if readOnly {
  101. options = append(options, "ro")
  102. }
  103. if notMnt {
  104. diskMounter := &mount.SafeFormatAndMount{Interface: mounter, Exec: attacher.host.GetExec(iscsiPluginName)}
  105. mountOptions := volumeutil.MountOptionFromSpec(spec, options...)
  106. err = diskMounter.FormatAndMount(devicePath, deviceMountPath, fsType, mountOptions)
  107. if err != nil {
  108. os.Remove(deviceMountPath)
  109. return err
  110. }
  111. }
  112. return nil
  113. }
  114. type iscsiDetacher struct {
  115. host volume.VolumeHost
  116. mounter mount.Interface
  117. manager diskManager
  118. plugin *iscsiPlugin
  119. }
  120. var _ volume.Detacher = &iscsiDetacher{}
  121. var _ volume.DeviceUnmounter = &iscsiDetacher{}
  122. func (plugin *iscsiPlugin) NewDetacher() (volume.Detacher, error) {
  123. return &iscsiDetacher{
  124. host: plugin.host,
  125. mounter: plugin.host.GetMounter(iscsiPluginName),
  126. manager: &ISCSIUtil{},
  127. plugin: plugin,
  128. }, nil
  129. }
  130. func (plugin *iscsiPlugin) NewDeviceUnmounter() (volume.DeviceUnmounter, error) {
  131. return plugin.NewDetacher()
  132. }
  133. func (detacher *iscsiDetacher) Detach(volumeName string, nodeName types.NodeName) error {
  134. return nil
  135. }
  136. func (detacher *iscsiDetacher) UnmountDevice(deviceMountPath string) error {
  137. unMounter := volumeSpecToUnmounter(detacher.mounter, detacher.host, detacher.plugin)
  138. err := detacher.manager.DetachDisk(*unMounter, deviceMountPath)
  139. if err != nil {
  140. return fmt.Errorf("iscsi: failed to detach disk: %s\nError: %v", deviceMountPath, err)
  141. }
  142. klog.V(4).Infof("iscsi: %q is unmounted, deleting the directory", deviceMountPath)
  143. err = os.RemoveAll(deviceMountPath)
  144. if err != nil {
  145. return fmt.Errorf("iscsi: failed to delete the directory: %s\nError: %v", deviceMountPath, err)
  146. }
  147. klog.V(4).Infof("iscsi: successfully detached disk: %s", deviceMountPath)
  148. return nil
  149. }
  150. func (plugin *iscsiPlugin) CanAttach(spec *volume.Spec) (bool, error) {
  151. return true, nil
  152. }
  153. func (plugin *iscsiPlugin) CanDeviceMount(spec *volume.Spec) (bool, error) {
  154. return true, nil
  155. }
  156. func volumeSpecToMounter(spec *volume.Spec, host volume.VolumeHost, targetLocks keymutex.KeyMutex, pod *v1.Pod) (*iscsiDiskMounter, error) {
  157. var secret map[string]string
  158. readOnly, fsType, err := getISCSIVolumeInfo(spec)
  159. if err != nil {
  160. return nil, err
  161. }
  162. var podUID types.UID
  163. if pod != nil {
  164. secret, err = createSecretMap(spec, &iscsiPlugin{host: host, targetLocks: targetLocks}, pod.Namespace)
  165. if err != nil {
  166. return nil, err
  167. }
  168. podUID = pod.UID
  169. }
  170. iscsiDisk, err := createISCSIDisk(spec,
  171. podUID,
  172. &iscsiPlugin{host: host, targetLocks: targetLocks},
  173. &ISCSIUtil{},
  174. secret,
  175. )
  176. if err != nil {
  177. return nil, err
  178. }
  179. exec := host.GetExec(iscsiPluginName)
  180. // TODO: remove feature gate check after no longer needed
  181. if utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
  182. volumeMode, err := volumeutil.GetVolumeMode(spec)
  183. if err != nil {
  184. return nil, err
  185. }
  186. klog.V(5).Infof("iscsi: VolumeSpecToMounter volumeMode %s", volumeMode)
  187. return &iscsiDiskMounter{
  188. iscsiDisk: iscsiDisk,
  189. fsType: fsType,
  190. volumeMode: volumeMode,
  191. readOnly: readOnly,
  192. mounter: &mount.SafeFormatAndMount{Interface: host.GetMounter(iscsiPluginName), Exec: exec},
  193. exec: exec,
  194. deviceUtil: volumeutil.NewDeviceHandler(volumeutil.NewIOHandler()),
  195. }, nil
  196. }
  197. return &iscsiDiskMounter{
  198. iscsiDisk: iscsiDisk,
  199. fsType: fsType,
  200. readOnly: readOnly,
  201. mounter: &mount.SafeFormatAndMount{Interface: host.GetMounter(iscsiPluginName), Exec: exec},
  202. exec: exec,
  203. deviceUtil: volumeutil.NewDeviceHandler(volumeutil.NewIOHandler()),
  204. }, nil
  205. }
  206. func volumeSpecToUnmounter(mounter mount.Interface, host volume.VolumeHost, plugin *iscsiPlugin) *iscsiDiskUnmounter {
  207. exec := host.GetExec(iscsiPluginName)
  208. return &iscsiDiskUnmounter{
  209. iscsiDisk: &iscsiDisk{
  210. plugin: plugin,
  211. },
  212. mounter: mounter,
  213. exec: exec,
  214. deviceUtil: volumeutil.NewDeviceHandler(volumeutil.NewIOHandler()),
  215. }
  216. }