iscsi.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. /*
  2. Copyright 2015 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. "context"
  16. "fmt"
  17. "os"
  18. "path/filepath"
  19. "strconv"
  20. "strings"
  21. "k8s.io/klog"
  22. utilexec "k8s.io/utils/exec"
  23. "k8s.io/utils/keymutex"
  24. "k8s.io/utils/mount"
  25. utilstrings "k8s.io/utils/strings"
  26. v1 "k8s.io/api/core/v1"
  27. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  28. "k8s.io/apimachinery/pkg/types"
  29. "k8s.io/kubernetes/pkg/volume"
  30. ioutil "k8s.io/kubernetes/pkg/volume/util"
  31. "k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
  32. )
  33. // This is the primary entrypoint for volume plugins.
  34. func ProbeVolumePlugins() []volume.VolumePlugin {
  35. return []volume.VolumePlugin{&iscsiPlugin{}}
  36. }
  37. type iscsiPlugin struct {
  38. host volume.VolumeHost
  39. targetLocks keymutex.KeyMutex
  40. }
  41. var _ volume.VolumePlugin = &iscsiPlugin{}
  42. var _ volume.PersistentVolumePlugin = &iscsiPlugin{}
  43. var _ volume.BlockVolumePlugin = &iscsiPlugin{}
  44. const (
  45. iscsiPluginName = "kubernetes.io/iscsi"
  46. )
  47. func (plugin *iscsiPlugin) Init(host volume.VolumeHost) error {
  48. plugin.host = host
  49. plugin.targetLocks = keymutex.NewHashed(0)
  50. return nil
  51. }
  52. func (plugin *iscsiPlugin) GetPluginName() string {
  53. return iscsiPluginName
  54. }
  55. func (plugin *iscsiPlugin) GetVolumeName(spec *volume.Spec) (string, error) {
  56. tp, _, iqn, lun, err := getISCSITargetInfo(spec)
  57. if err != nil {
  58. return "", err
  59. }
  60. return fmt.Sprintf("%v:%v:%v", tp, iqn, lun), nil
  61. }
  62. func (plugin *iscsiPlugin) CanSupport(spec *volume.Spec) bool {
  63. return (spec.Volume != nil && spec.Volume.ISCSI != nil) || (spec.PersistentVolume != nil && spec.PersistentVolume.Spec.ISCSI != nil)
  64. }
  65. func (plugin *iscsiPlugin) RequiresRemount() bool {
  66. return false
  67. }
  68. func (plugin *iscsiPlugin) SupportsMountOption() bool {
  69. return true
  70. }
  71. func (plugin *iscsiPlugin) SupportsBulkVolumeVerification() bool {
  72. return false
  73. }
  74. func (plugin *iscsiPlugin) GetAccessModes() []v1.PersistentVolumeAccessMode {
  75. return []v1.PersistentVolumeAccessMode{
  76. v1.ReadWriteOnce,
  77. v1.ReadOnlyMany,
  78. }
  79. }
  80. func (plugin *iscsiPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
  81. if pod == nil {
  82. return nil, fmt.Errorf("nil pod")
  83. }
  84. secret, err := createSecretMap(spec, plugin, pod.Namespace)
  85. if err != nil {
  86. return nil, err
  87. }
  88. return plugin.newMounterInternal(spec, pod.UID, &ISCSIUtil{}, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName()), secret)
  89. }
  90. func (plugin *iscsiPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, manager diskManager, mounter mount.Interface, exec utilexec.Interface, secret map[string]string) (volume.Mounter, error) {
  91. readOnly, fsType, err := getISCSIVolumeInfo(spec)
  92. if err != nil {
  93. return nil, err
  94. }
  95. iscsiDisk, err := createISCSIDisk(spec, podUID, plugin, manager, secret)
  96. if err != nil {
  97. return nil, err
  98. }
  99. if iscsiDisk != nil {
  100. //Add volume metrics
  101. iscsiDisk.MetricsProvider = volume.NewMetricsStatFS(iscsiDisk.GetPath())
  102. }
  103. return &iscsiDiskMounter{
  104. iscsiDisk: iscsiDisk,
  105. fsType: fsType,
  106. readOnly: readOnly,
  107. mounter: &mount.SafeFormatAndMount{Interface: mounter, Exec: exec},
  108. exec: exec,
  109. deviceUtil: ioutil.NewDeviceHandler(ioutil.NewIOHandler()),
  110. mountOptions: ioutil.MountOptionFromSpec(spec),
  111. }, nil
  112. }
  113. // NewBlockVolumeMapper creates a new volume.BlockVolumeMapper from an API specification.
  114. func (plugin *iscsiPlugin) NewBlockVolumeMapper(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.BlockVolumeMapper, error) {
  115. // If this is called via GenerateUnmapDeviceFunc(), pod is nil.
  116. // Pass empty string as dummy uid since uid isn't used in the case.
  117. var uid types.UID
  118. var secret map[string]string
  119. var err error
  120. if pod != nil {
  121. uid = pod.UID
  122. secret, err = createSecretMap(spec, plugin, pod.Namespace)
  123. if err != nil {
  124. return nil, err
  125. }
  126. }
  127. return plugin.newBlockVolumeMapperInternal(spec, uid, &ISCSIUtil{}, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName()), secret)
  128. }
  129. func (plugin *iscsiPlugin) newBlockVolumeMapperInternal(spec *volume.Spec, podUID types.UID, manager diskManager, mounter mount.Interface, exec utilexec.Interface, secret map[string]string) (volume.BlockVolumeMapper, error) {
  130. readOnly, _, err := getISCSIVolumeInfo(spec)
  131. if err != nil {
  132. return nil, err
  133. }
  134. iscsiDisk, err := createISCSIDisk(spec, podUID, plugin, manager, secret)
  135. if err != nil {
  136. return nil, err
  137. }
  138. return &iscsiDiskMapper{
  139. iscsiDisk: iscsiDisk,
  140. readOnly: readOnly,
  141. exec: exec,
  142. deviceUtil: ioutil.NewDeviceHandler(ioutil.NewIOHandler()),
  143. }, nil
  144. }
  145. func (plugin *iscsiPlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
  146. return plugin.newUnmounterInternal(volName, podUID, &ISCSIUtil{}, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName()))
  147. }
  148. func (plugin *iscsiPlugin) newUnmounterInternal(volName string, podUID types.UID, manager diskManager, mounter mount.Interface, exec utilexec.Interface) (volume.Unmounter, error) {
  149. return &iscsiDiskUnmounter{
  150. iscsiDisk: &iscsiDisk{
  151. podUID: podUID,
  152. VolName: volName,
  153. manager: manager,
  154. plugin: plugin,
  155. MetricsProvider: volume.NewMetricsStatFS(plugin.host.GetPodVolumeDir(podUID, utilstrings.EscapeQualifiedName(iscsiPluginName), volName)),
  156. },
  157. mounter: mounter,
  158. exec: exec,
  159. deviceUtil: ioutil.NewDeviceHandler(ioutil.NewIOHandler()),
  160. }, nil
  161. }
  162. // NewBlockVolumeUnmapper creates a new volume.BlockVolumeUnmapper from recoverable state.
  163. func (plugin *iscsiPlugin) NewBlockVolumeUnmapper(volName string, podUID types.UID) (volume.BlockVolumeUnmapper, error) {
  164. return plugin.newUnmapperInternal(volName, podUID, &ISCSIUtil{}, plugin.host.GetExec(plugin.GetPluginName()))
  165. }
  166. func (plugin *iscsiPlugin) newUnmapperInternal(volName string, podUID types.UID, manager diskManager, exec utilexec.Interface) (volume.BlockVolumeUnmapper, error) {
  167. return &iscsiDiskUnmapper{
  168. iscsiDisk: &iscsiDisk{
  169. podUID: podUID,
  170. VolName: volName,
  171. manager: manager,
  172. plugin: plugin,
  173. },
  174. exec: exec,
  175. deviceUtil: ioutil.NewDeviceHandler(ioutil.NewIOHandler()),
  176. }, nil
  177. }
  178. func (plugin *iscsiPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) {
  179. // Find globalPDPath from pod volume directory(mountPath)
  180. var globalPDPath string
  181. mounter := plugin.host.GetMounter(plugin.GetPluginName())
  182. paths, err := mounter.GetMountRefs(mountPath)
  183. if err != nil {
  184. return nil, err
  185. }
  186. for _, path := range paths {
  187. if strings.Contains(path, plugin.host.GetPluginDir(iscsiPluginName)) {
  188. globalPDPath = path
  189. break
  190. }
  191. }
  192. // Couldn't fetch globalPDPath
  193. if len(globalPDPath) == 0 {
  194. return nil, fmt.Errorf("couldn't fetch globalPDPath. failed to obtain volume spec")
  195. }
  196. // Obtain iscsi disk configurations from globalPDPath
  197. device, _, err := extractDeviceAndPrefix(globalPDPath)
  198. if err != nil {
  199. return nil, err
  200. }
  201. bkpPortal, iqn, err := extractPortalAndIqn(device)
  202. if err != nil {
  203. return nil, err
  204. }
  205. arr := strings.Split(device, "-lun-")
  206. if len(arr) < 2 {
  207. return nil, fmt.Errorf("failed to retrieve lun from globalPDPath: %v", globalPDPath)
  208. }
  209. lun, err := strconv.Atoi(arr[1])
  210. if err != nil {
  211. return nil, err
  212. }
  213. iface, _ := extractIface(globalPDPath)
  214. iscsiVolume := &v1.Volume{
  215. Name: volumeName,
  216. VolumeSource: v1.VolumeSource{
  217. ISCSI: &v1.ISCSIVolumeSource{
  218. TargetPortal: bkpPortal,
  219. IQN: iqn,
  220. Lun: int32(lun),
  221. ISCSIInterface: iface,
  222. },
  223. },
  224. }
  225. return volume.NewSpecFromVolume(iscsiVolume), nil
  226. }
  227. func (plugin *iscsiPlugin) ConstructBlockVolumeSpec(podUID types.UID, volumeName, mapPath string) (*volume.Spec, error) {
  228. pluginDir := plugin.host.GetVolumeDevicePluginDir(iscsiPluginName)
  229. blkutil := volumepathhandler.NewBlockVolumePathHandler()
  230. globalMapPathUUID, err := blkutil.FindGlobalMapPathUUIDFromPod(pluginDir, mapPath, podUID)
  231. if err != nil {
  232. return nil, err
  233. }
  234. klog.V(5).Infof("globalMapPathUUID: %v, err: %v", globalMapPathUUID, err)
  235. // Retrieve volume information from globalMapPathUUID
  236. // globalMapPathUUID example:
  237. // plugins/kubernetes.io/{PluginName}/{DefaultKubeletVolumeDevicesDirName}/{volumePluginDependentPath}/{pod uuid}
  238. // plugins/kubernetes.io/iscsi/volumeDevices/iface-default/192.168.0.10:3260-iqn.2017-05.com.example:test-lun-0/{pod uuid}
  239. globalMapPath := filepath.Dir(globalMapPathUUID)
  240. return getVolumeSpecFromGlobalMapPath(volumeName, globalMapPath)
  241. }
  242. type iscsiDisk struct {
  243. VolName string
  244. podUID types.UID
  245. Portals []string
  246. Iqn string
  247. Lun string
  248. InitIface string
  249. Iface string
  250. chapDiscovery bool
  251. chapSession bool
  252. secret map[string]string
  253. InitiatorName string
  254. plugin *iscsiPlugin
  255. // Utility interface that provides API calls to the provider to attach/detach disks.
  256. manager diskManager
  257. volume.MetricsProvider
  258. }
  259. func (iscsi *iscsiDisk) GetPath() string {
  260. name := iscsiPluginName
  261. // safe to use PodVolumeDir now: volume teardown occurs before pod is cleaned up
  262. return iscsi.plugin.host.GetPodVolumeDir(iscsi.podUID, utilstrings.EscapeQualifiedName(name), iscsi.VolName)
  263. }
  264. func (iscsi *iscsiDisk) iscsiGlobalMapPath(spec *volume.Spec) (string, error) {
  265. mounter, err := volumeSpecToMounter(spec, iscsi.plugin.host, iscsi.plugin.targetLocks, nil /* pod */)
  266. if err != nil {
  267. klog.Warningf("failed to get iscsi mounter: %v", err)
  268. return "", err
  269. }
  270. return iscsi.manager.MakeGlobalVDPDName(*mounter.iscsiDisk), nil
  271. }
  272. func (iscsi *iscsiDisk) iscsiPodDeviceMapPath() (string, string) {
  273. name := iscsiPluginName
  274. return iscsi.plugin.host.GetPodVolumeDeviceDir(iscsi.podUID, utilstrings.EscapeQualifiedName(name)), iscsi.VolName
  275. }
  276. type iscsiDiskMounter struct {
  277. *iscsiDisk
  278. readOnly bool
  279. fsType string
  280. volumeMode v1.PersistentVolumeMode
  281. mounter *mount.SafeFormatAndMount
  282. exec utilexec.Interface
  283. deviceUtil ioutil.DeviceUtil
  284. mountOptions []string
  285. }
  286. var _ volume.Mounter = &iscsiDiskMounter{}
  287. func (b *iscsiDiskMounter) GetAttributes() volume.Attributes {
  288. return volume.Attributes{
  289. ReadOnly: b.readOnly,
  290. Managed: !b.readOnly,
  291. SupportsSELinux: true,
  292. }
  293. }
  294. // Checks prior to mount operations to verify that the required components (binaries, etc.)
  295. // to mount the volume are available on the underlying node.
  296. // If not, it returns an error
  297. func (b *iscsiDiskMounter) CanMount() error {
  298. return nil
  299. }
  300. func (b *iscsiDiskMounter) SetUp(mounterArgs volume.MounterArgs) error {
  301. return b.SetUpAt(b.GetPath(), mounterArgs)
  302. }
  303. func (b *iscsiDiskMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
  304. // diskSetUp checks mountpoints and prevent repeated calls
  305. err := diskSetUp(b.manager, *b, dir, b.mounter, mounterArgs.FsGroup)
  306. if err != nil {
  307. klog.Errorf("iscsi: failed to setup")
  308. }
  309. return err
  310. }
  311. type iscsiDiskUnmounter struct {
  312. *iscsiDisk
  313. mounter mount.Interface
  314. exec utilexec.Interface
  315. deviceUtil ioutil.DeviceUtil
  316. }
  317. var _ volume.Unmounter = &iscsiDiskUnmounter{}
  318. // Unmounts the bind mount, and detaches the disk only if the disk
  319. // resource was the last reference to that disk on the kubelet.
  320. func (c *iscsiDiskUnmounter) TearDown() error {
  321. return c.TearDownAt(c.GetPath())
  322. }
  323. func (c *iscsiDiskUnmounter) TearDownAt(dir string) error {
  324. return mount.CleanupMountPoint(dir, c.mounter, false)
  325. }
  326. // Block Volumes Support
  327. type iscsiDiskMapper struct {
  328. *iscsiDisk
  329. readOnly bool
  330. exec utilexec.Interface
  331. deviceUtil ioutil.DeviceUtil
  332. }
  333. var _ volume.BlockVolumeMapper = &iscsiDiskMapper{}
  334. type iscsiDiskUnmapper struct {
  335. *iscsiDisk
  336. exec utilexec.Interface
  337. deviceUtil ioutil.DeviceUtil
  338. }
  339. var _ volume.BlockVolumeUnmapper = &iscsiDiskUnmapper{}
  340. var _ volume.CustomBlockVolumeUnmapper = &iscsiDiskUnmapper{}
  341. // Even though iSCSI plugin has attacher/detacher implementation, iSCSI plugin
  342. // needs volume detach operation during TearDownDevice(). This method is only
  343. // chance that operations are done on kubelet node during volume teardown sequences.
  344. func (c *iscsiDiskUnmapper) TearDownDevice(mapPath, _ string) error {
  345. err := c.manager.DetachBlockISCSIDisk(*c, mapPath)
  346. if err != nil {
  347. return fmt.Errorf("iscsi: failed to detach disk: %s\nError: %v", mapPath, err)
  348. }
  349. klog.V(4).Infof("iscsi: %q is unmounted, deleting the directory", mapPath)
  350. err = os.RemoveAll(mapPath)
  351. if err != nil {
  352. return fmt.Errorf("iscsi: failed to delete the directory: %s\nError: %v", mapPath, err)
  353. }
  354. klog.V(4).Infof("iscsi: successfully detached disk: %s", mapPath)
  355. return nil
  356. }
  357. func (c *iscsiDiskUnmapper) UnmapPodDevice() error {
  358. return nil
  359. }
  360. // GetGlobalMapPath returns global map path and error
  361. // path: plugins/kubernetes.io/{PluginName}/volumeDevices/{ifaceName}/{portal-some_iqn-lun-lun_id}
  362. func (iscsi *iscsiDisk) GetGlobalMapPath(spec *volume.Spec) (string, error) {
  363. return iscsi.iscsiGlobalMapPath(spec)
  364. }
  365. // GetPodDeviceMapPath returns pod device map path and volume name
  366. // path: pods/{podUid}/volumeDevices/kubernetes.io~iscsi
  367. // volumeName: pv0001
  368. func (iscsi *iscsiDisk) GetPodDeviceMapPath() (string, string) {
  369. return iscsi.iscsiPodDeviceMapPath()
  370. }
  371. func portalMounter(portal string) string {
  372. if !strings.Contains(portal, ":") {
  373. portal = portal + ":3260"
  374. }
  375. return portal
  376. }
  377. // get iSCSI volume info: readOnly and fstype
  378. func getISCSIVolumeInfo(spec *volume.Spec) (bool, string, error) {
  379. // for volume source, readonly is in volume spec
  380. // for PV, readonly is in PV spec. PV gets the ReadOnly flag indirectly through the PVC source
  381. if spec.Volume != nil && spec.Volume.ISCSI != nil {
  382. return spec.Volume.ISCSI.ReadOnly, spec.Volume.ISCSI.FSType, nil
  383. } else if spec.PersistentVolume != nil &&
  384. spec.PersistentVolume.Spec.ISCSI != nil {
  385. return spec.ReadOnly, spec.PersistentVolume.Spec.ISCSI.FSType, nil
  386. }
  387. return false, "", fmt.Errorf("Spec does not reference an ISCSI volume type")
  388. }
  389. // get iSCSI target info: target portal, portals, iqn, and lun
  390. func getISCSITargetInfo(spec *volume.Spec) (string, []string, string, int32, error) {
  391. if spec.Volume != nil && spec.Volume.ISCSI != nil {
  392. return spec.Volume.ISCSI.TargetPortal, spec.Volume.ISCSI.Portals, spec.Volume.ISCSI.IQN, spec.Volume.ISCSI.Lun, nil
  393. } else if spec.PersistentVolume != nil &&
  394. spec.PersistentVolume.Spec.ISCSI != nil {
  395. return spec.PersistentVolume.Spec.ISCSI.TargetPortal, spec.PersistentVolume.Spec.ISCSI.Portals, spec.PersistentVolume.Spec.ISCSI.IQN, spec.PersistentVolume.Spec.ISCSI.Lun, nil
  396. }
  397. return "", nil, "", 0, fmt.Errorf("Spec does not reference an ISCSI volume type")
  398. }
  399. // get iSCSI initiator info: iface and initiator name
  400. func getISCSIInitiatorInfo(spec *volume.Spec) (string, *string, error) {
  401. if spec.Volume != nil && spec.Volume.ISCSI != nil {
  402. return spec.Volume.ISCSI.ISCSIInterface, spec.Volume.ISCSI.InitiatorName, nil
  403. } else if spec.PersistentVolume != nil &&
  404. spec.PersistentVolume.Spec.ISCSI != nil {
  405. return spec.PersistentVolume.Spec.ISCSI.ISCSIInterface, spec.PersistentVolume.Spec.ISCSI.InitiatorName, nil
  406. }
  407. return "", nil, fmt.Errorf("Spec does not reference an ISCSI volume type")
  408. }
  409. // get iSCSI Discovery CHAP boolean
  410. func getISCSIDiscoveryCHAPInfo(spec *volume.Spec) (bool, error) {
  411. if spec.Volume != nil && spec.Volume.ISCSI != nil {
  412. return spec.Volume.ISCSI.DiscoveryCHAPAuth, nil
  413. } else if spec.PersistentVolume != nil &&
  414. spec.PersistentVolume.Spec.ISCSI != nil {
  415. return spec.PersistentVolume.Spec.ISCSI.DiscoveryCHAPAuth, nil
  416. }
  417. return false, fmt.Errorf("Spec does not reference an ISCSI volume type")
  418. }
  419. // get iSCSI Session CHAP boolean
  420. func getISCSISessionCHAPInfo(spec *volume.Spec) (bool, error) {
  421. if spec.Volume != nil && spec.Volume.ISCSI != nil {
  422. return spec.Volume.ISCSI.SessionCHAPAuth, nil
  423. } else if spec.PersistentVolume != nil &&
  424. spec.PersistentVolume.Spec.ISCSI != nil {
  425. return spec.PersistentVolume.Spec.ISCSI.SessionCHAPAuth, nil
  426. }
  427. return false, fmt.Errorf("Spec does not reference an ISCSI volume type")
  428. }
  429. // get iSCSI CHAP Secret info: secret name and namespace
  430. func getISCSISecretNameAndNamespace(spec *volume.Spec, defaultSecretNamespace string) (string, string, error) {
  431. if spec.Volume != nil && spec.Volume.ISCSI != nil {
  432. if spec.Volume.ISCSI.SecretRef != nil {
  433. return spec.Volume.ISCSI.SecretRef.Name, defaultSecretNamespace, nil
  434. }
  435. return "", "", nil
  436. } else if spec.PersistentVolume != nil &&
  437. spec.PersistentVolume.Spec.ISCSI != nil {
  438. secretRef := spec.PersistentVolume.Spec.ISCSI.SecretRef
  439. secretNs := defaultSecretNamespace
  440. if secretRef != nil {
  441. if len(secretRef.Namespace) != 0 {
  442. secretNs = secretRef.Namespace
  443. }
  444. return secretRef.Name, secretNs, nil
  445. }
  446. return "", "", nil
  447. }
  448. return "", "", fmt.Errorf("Spec does not reference an ISCSI volume type")
  449. }
  450. func createISCSIDisk(spec *volume.Spec, podUID types.UID, plugin *iscsiPlugin, manager diskManager, secret map[string]string) (*iscsiDisk, error) {
  451. tp, portals, iqn, lunStr, err := getISCSITargetInfo(spec)
  452. if err != nil {
  453. return nil, err
  454. }
  455. lun := strconv.Itoa(int(lunStr))
  456. portal := portalMounter(tp)
  457. var bkportal []string
  458. bkportal = append(bkportal, portal)
  459. for _, p := range portals {
  460. bkportal = append(bkportal, portalMounter(string(p)))
  461. }
  462. iface, initiatorNamePtr, err := getISCSIInitiatorInfo(spec)
  463. if err != nil {
  464. return nil, err
  465. }
  466. var initiatorName string
  467. if initiatorNamePtr != nil {
  468. initiatorName = *initiatorNamePtr
  469. }
  470. chapDiscovery, err := getISCSIDiscoveryCHAPInfo(spec)
  471. if err != nil {
  472. return nil, err
  473. }
  474. chapSession, err := getISCSISessionCHAPInfo(spec)
  475. if err != nil {
  476. return nil, err
  477. }
  478. initIface := iface
  479. if initiatorName != "" {
  480. iface = bkportal[0] + ":" + spec.Name()
  481. }
  482. return &iscsiDisk{
  483. podUID: podUID,
  484. VolName: spec.Name(),
  485. Portals: bkportal,
  486. Iqn: iqn,
  487. Lun: lun,
  488. InitIface: initIface,
  489. Iface: iface,
  490. chapDiscovery: chapDiscovery,
  491. chapSession: chapSession,
  492. secret: secret,
  493. InitiatorName: initiatorName,
  494. manager: manager,
  495. plugin: plugin}, nil
  496. }
  497. func createSecretMap(spec *volume.Spec, plugin *iscsiPlugin, namespace string) (map[string]string, error) {
  498. var secret map[string]string
  499. chapDiscover, err := getISCSIDiscoveryCHAPInfo(spec)
  500. if err != nil {
  501. return nil, err
  502. }
  503. chapSession, err := getISCSISessionCHAPInfo(spec)
  504. if err != nil {
  505. return nil, err
  506. }
  507. if chapDiscover || chapSession {
  508. secretName, secretNamespace, err := getISCSISecretNameAndNamespace(spec, namespace)
  509. if err != nil {
  510. return nil, err
  511. }
  512. if len(secretName) > 0 && len(secretNamespace) > 0 {
  513. // if secret is provideded, retrieve it
  514. kubeClient := plugin.host.GetKubeClient()
  515. if kubeClient == nil {
  516. return nil, fmt.Errorf("Cannot get kube client")
  517. }
  518. secretObj, err := kubeClient.CoreV1().Secrets(secretNamespace).Get(context.TODO(), secretName, metav1.GetOptions{})
  519. if err != nil {
  520. err = fmt.Errorf("Couldn't get secret %v/%v error: %v", secretNamespace, secretName, err)
  521. return nil, err
  522. }
  523. secret = make(map[string]string)
  524. for name, data := range secretObj.Data {
  525. klog.V(4).Infof("retrieving CHAP secret name: %s", name)
  526. secret[name] = string(data)
  527. }
  528. }
  529. }
  530. return secret, err
  531. }
  532. func createPersistentVolumeFromISCSIPVSource(volumeName string, iscsi v1.ISCSIPersistentVolumeSource) *v1.PersistentVolume {
  533. block := v1.PersistentVolumeBlock
  534. return &v1.PersistentVolume{
  535. ObjectMeta: metav1.ObjectMeta{
  536. Name: volumeName,
  537. },
  538. Spec: v1.PersistentVolumeSpec{
  539. PersistentVolumeSource: v1.PersistentVolumeSource{
  540. ISCSI: &iscsi,
  541. },
  542. VolumeMode: &block,
  543. },
  544. }
  545. }
  546. func getVolumeSpecFromGlobalMapPath(volumeName, globalMapPath string) (*volume.Spec, error) {
  547. // Retrieve volume spec information from globalMapPath
  548. // globalMapPath example:
  549. // plugins/kubernetes.io/{PluginName}/{DefaultKubeletVolumeDevicesDirName}/{volumePluginDependentPath}
  550. // plugins/kubernetes.io/iscsi/volumeDevices/iface-default/192.168.0.10:3260-iqn.2017-05.com.example:test-lun-0
  551. // device: 192.168.0.10:3260-iqn.2017-05.com.example:test-lun-0
  552. device, _, err := extractDeviceAndPrefix(globalMapPath)
  553. if err != nil {
  554. return nil, err
  555. }
  556. bkpPortal, iqn, err := extractPortalAndIqn(device)
  557. if err != nil {
  558. return nil, err
  559. }
  560. arr := strings.Split(device, "-lun-")
  561. if len(arr) < 2 {
  562. return nil, fmt.Errorf("failed to retrieve lun from globalMapPath: %v", globalMapPath)
  563. }
  564. lun, err := strconv.Atoi(arr[1])
  565. if err != nil {
  566. return nil, err
  567. }
  568. iface, found := extractIface(globalMapPath)
  569. if !found {
  570. return nil, fmt.Errorf("failed to retrieve iface from globalMapPath: %v", globalMapPath)
  571. }
  572. iscsiPV := createPersistentVolumeFromISCSIPVSource(volumeName,
  573. v1.ISCSIPersistentVolumeSource{
  574. TargetPortal: bkpPortal,
  575. IQN: iqn,
  576. Lun: int32(lun),
  577. ISCSIInterface: iface,
  578. },
  579. )
  580. klog.V(5).Infof("ConstructBlockVolumeSpec: TargetPortal: %v, IQN: %v, Lun: %v, ISCSIInterface: %v",
  581. iscsiPV.Spec.PersistentVolumeSource.ISCSI.TargetPortal,
  582. iscsiPV.Spec.PersistentVolumeSource.ISCSI.IQN,
  583. iscsiPV.Spec.PersistentVolumeSource.ISCSI.Lun,
  584. iscsiPV.Spec.PersistentVolumeSource.ISCSI.ISCSIInterface,
  585. )
  586. return volume.NewSpecFromPersistentVolume(iscsiPV, false), nil
  587. }