rbd.go 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131
  1. /*
  2. Copyright 2014 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. "path/filepath"
  18. "regexp"
  19. dstrings "strings"
  20. "k8s.io/api/core/v1"
  21. "k8s.io/apimachinery/pkg/api/resource"
  22. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  23. "k8s.io/apimachinery/pkg/types"
  24. "k8s.io/apimachinery/pkg/util/sets"
  25. "k8s.io/apimachinery/pkg/util/uuid"
  26. utilfeature "k8s.io/apiserver/pkg/util/feature"
  27. clientset "k8s.io/client-go/kubernetes"
  28. "k8s.io/klog"
  29. "k8s.io/kubernetes/pkg/features"
  30. "k8s.io/kubernetes/pkg/util/mount"
  31. "k8s.io/kubernetes/pkg/volume"
  32. volutil "k8s.io/kubernetes/pkg/volume/util"
  33. "k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
  34. utilstrings "k8s.io/utils/strings"
  35. )
  36. var (
  37. supportedFeatures = sets.NewString("layering")
  38. )
  39. // This is the primary entrypoint for volume plugins.
  40. func ProbeVolumePlugins() []volume.VolumePlugin {
  41. return []volume.VolumePlugin{&rbdPlugin{}}
  42. }
  43. // rbdPlugin implements Volume.VolumePlugin.
  44. type rbdPlugin struct {
  45. host volume.VolumeHost
  46. }
  47. var _ volume.VolumePlugin = &rbdPlugin{}
  48. var _ volume.PersistentVolumePlugin = &rbdPlugin{}
  49. var _ volume.DeletableVolumePlugin = &rbdPlugin{}
  50. var _ volume.ProvisionableVolumePlugin = &rbdPlugin{}
  51. var _ volume.AttachableVolumePlugin = &rbdPlugin{}
  52. var _ volume.ExpandableVolumePlugin = &rbdPlugin{}
  53. var _ volume.BlockVolumePlugin = &rbdPlugin{}
  54. var _ volume.DeviceMountableVolumePlugin = &rbdPlugin{}
  55. const (
  56. rbdPluginName = "kubernetes.io/rbd"
  57. secretKeyName = "key" // key name used in secret
  58. rbdImageFormat1 = "1"
  59. rbdImageFormat2 = "2"
  60. rbdDefaultAdminId = "admin"
  61. rbdDefaultAdminSecretNamespace = "default"
  62. rbdDefaultPool = "rbd"
  63. rbdDefaultUserId = rbdDefaultAdminId
  64. )
  65. func getPath(uid types.UID, volName string, host volume.VolumeHost) string {
  66. return host.GetPodVolumeDir(uid, utilstrings.EscapeQualifiedName(rbdPluginName), volName)
  67. }
  68. func (plugin *rbdPlugin) Init(host volume.VolumeHost) error {
  69. plugin.host = host
  70. return nil
  71. }
  72. func (plugin *rbdPlugin) GetPluginName() string {
  73. return rbdPluginName
  74. }
  75. func (plugin *rbdPlugin) GetVolumeName(spec *volume.Spec) (string, error) {
  76. pool, err := getVolumeSourcePool(spec)
  77. if err != nil {
  78. return "", err
  79. }
  80. img, err := getVolumeSourceImage(spec)
  81. if err != nil {
  82. return "", err
  83. }
  84. return fmt.Sprintf(
  85. "%v:%v",
  86. pool,
  87. img), nil
  88. }
  89. func (plugin *rbdPlugin) CanSupport(spec *volume.Spec) bool {
  90. return (spec.Volume != nil && spec.Volume.RBD != nil) || (spec.PersistentVolume != nil && spec.PersistentVolume.Spec.RBD != nil)
  91. }
  92. func (plugin *rbdPlugin) IsMigratedToCSI() bool {
  93. return false
  94. }
  95. func (plugin *rbdPlugin) RequiresRemount() bool {
  96. return false
  97. }
  98. func (plugin *rbdPlugin) SupportsMountOption() bool {
  99. return true
  100. }
  101. func (plugin *rbdPlugin) SupportsBulkVolumeVerification() bool {
  102. return false
  103. }
  104. func (plugin *rbdPlugin) GetAccessModes() []v1.PersistentVolumeAccessMode {
  105. return []v1.PersistentVolumeAccessMode{
  106. v1.ReadWriteOnce,
  107. v1.ReadOnlyMany,
  108. }
  109. }
  110. type rbdVolumeExpander struct {
  111. *rbdMounter
  112. }
  113. func (plugin *rbdPlugin) getAdminAndSecret(spec *volume.Spec) (string, string, error) {
  114. class, err := volutil.GetClassForVolume(plugin.host.GetKubeClient(), spec.PersistentVolume)
  115. if err != nil {
  116. return "", "", err
  117. }
  118. adminSecretName := ""
  119. adminSecretNamespace := rbdDefaultAdminSecretNamespace
  120. admin := ""
  121. for k, v := range class.Parameters {
  122. switch dstrings.ToLower(k) {
  123. case "adminid":
  124. admin = v
  125. case "adminsecretname":
  126. adminSecretName = v
  127. case "adminsecretnamespace":
  128. adminSecretNamespace = v
  129. }
  130. }
  131. if admin == "" {
  132. admin = rbdDefaultAdminId
  133. }
  134. secret, err := parsePVSecret(adminSecretNamespace, adminSecretName, plugin.host.GetKubeClient())
  135. if err != nil {
  136. return admin, "", fmt.Errorf("failed to get admin secret from [%q/%q]: %v", adminSecretNamespace, adminSecretName, err)
  137. }
  138. return admin, secret, nil
  139. }
  140. func (plugin *rbdPlugin) ExpandVolumeDevice(spec *volume.Spec, newSize resource.Quantity, oldSize resource.Quantity) (resource.Quantity, error) {
  141. if spec.PersistentVolume != nil && spec.PersistentVolume.Spec.RBD == nil {
  142. return oldSize, fmt.Errorf("spec.PersistentVolume.Spec.RBD is nil")
  143. }
  144. // get admin and secret
  145. admin, secret, err := plugin.getAdminAndSecret(spec)
  146. if err != nil {
  147. return oldSize, err
  148. }
  149. expander := &rbdVolumeExpander{
  150. rbdMounter: &rbdMounter{
  151. rbd: &rbd{
  152. volName: spec.Name(),
  153. Image: spec.PersistentVolume.Spec.RBD.RBDImage,
  154. Pool: spec.PersistentVolume.Spec.RBD.RBDPool,
  155. plugin: plugin,
  156. manager: &RBDUtil{},
  157. mounter: &mount.SafeFormatAndMount{Interface: plugin.host.GetMounter(plugin.GetPluginName())},
  158. exec: plugin.host.GetExec(plugin.GetPluginName()),
  159. },
  160. Mon: spec.PersistentVolume.Spec.RBD.CephMonitors,
  161. adminId: admin,
  162. adminSecret: secret,
  163. },
  164. }
  165. expandedSize, err := expander.ResizeImage(oldSize, newSize)
  166. if err != nil {
  167. return oldSize, err
  168. } else {
  169. return expandedSize, nil
  170. }
  171. }
  172. func (plugin *rbdPlugin) NodeExpand(resizeOptions volume.NodeResizeOptions) (bool, error) {
  173. _, err := volutil.GenericResizeFS(plugin.host, plugin.GetPluginName(), resizeOptions.DevicePath, resizeOptions.DeviceMountPath)
  174. if err != nil {
  175. return false, err
  176. }
  177. return true, nil
  178. }
  179. var _ volume.NodeExpandableVolumePlugin = &rbdPlugin{}
  180. func (expander *rbdVolumeExpander) ResizeImage(oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error) {
  181. return expander.manager.ExpandImage(expander, oldSize, newSize)
  182. }
  183. func (plugin *rbdPlugin) RequiresFSResize() bool {
  184. return true
  185. }
  186. func (plugin *rbdPlugin) createMounterFromVolumeSpecAndPod(spec *volume.Spec, pod *v1.Pod) (*rbdMounter, error) {
  187. var err error
  188. mon, err := getVolumeSourceMonitors(spec)
  189. if err != nil {
  190. return nil, err
  191. }
  192. img, err := getVolumeSourceImage(spec)
  193. if err != nil {
  194. return nil, err
  195. }
  196. fstype, err := getVolumeSourceFSType(spec)
  197. if err != nil {
  198. return nil, err
  199. }
  200. pool, err := getVolumeSourcePool(spec)
  201. if err != nil {
  202. return nil, err
  203. }
  204. id, err := getVolumeSourceUser(spec)
  205. if err != nil {
  206. return nil, err
  207. }
  208. keyring, err := getVolumeSourceKeyRing(spec)
  209. if err != nil {
  210. return nil, err
  211. }
  212. ro, err := getVolumeSourceReadOnly(spec)
  213. if err != nil {
  214. return nil, err
  215. }
  216. ams, err := getVolumeAccessModes(spec)
  217. if err != nil {
  218. return nil, err
  219. }
  220. secretName, secretNs, err := getSecretNameAndNamespace(spec, pod.Namespace)
  221. if err != nil {
  222. return nil, err
  223. }
  224. secret := ""
  225. if len(secretName) > 0 && len(secretNs) > 0 {
  226. // if secret is provideded, retrieve it
  227. kubeClient := plugin.host.GetKubeClient()
  228. if kubeClient == nil {
  229. return nil, fmt.Errorf("Cannot get kube client")
  230. }
  231. secrets, err := kubeClient.CoreV1().Secrets(secretNs).Get(secretName, metav1.GetOptions{})
  232. if err != nil {
  233. err = fmt.Errorf("Couldn't get secret %v/%v err: %v", secretNs, secretName, err)
  234. return nil, err
  235. }
  236. for _, data := range secrets.Data {
  237. secret = string(data)
  238. }
  239. }
  240. return &rbdMounter{
  241. rbd: newRBD("", spec.Name(), img, pool, ro, plugin, &RBDUtil{}),
  242. Mon: mon,
  243. Id: id,
  244. Keyring: keyring,
  245. Secret: secret,
  246. fsType: fstype,
  247. accessModes: ams,
  248. }, nil
  249. }
  250. func (plugin *rbdPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
  251. secretName, secretNs, err := getSecretNameAndNamespace(spec, pod.Namespace)
  252. if err != nil {
  253. return nil, err
  254. }
  255. secret := ""
  256. if len(secretName) > 0 && len(secretNs) > 0 {
  257. // if secret is provideded, retrieve it
  258. kubeClient := plugin.host.GetKubeClient()
  259. if kubeClient == nil {
  260. return nil, fmt.Errorf("Cannot get kube client")
  261. }
  262. secrets, err := kubeClient.CoreV1().Secrets(secretNs).Get(secretName, metav1.GetOptions{})
  263. if err != nil {
  264. err = fmt.Errorf("Couldn't get secret %v/%v err: %v", secretNs, secretName, err)
  265. return nil, err
  266. }
  267. for _, data := range secrets.Data {
  268. secret = string(data)
  269. }
  270. }
  271. // Inject real implementations here, test through the internal function.
  272. return plugin.newMounterInternal(spec, pod.UID, &RBDUtil{}, secret)
  273. }
  274. func (plugin *rbdPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, manager diskManager, secret string) (volume.Mounter, error) {
  275. mon, err := getVolumeSourceMonitors(spec)
  276. if err != nil {
  277. return nil, err
  278. }
  279. img, err := getVolumeSourceImage(spec)
  280. if err != nil {
  281. return nil, err
  282. }
  283. fstype, err := getVolumeSourceFSType(spec)
  284. if err != nil {
  285. return nil, err
  286. }
  287. pool, err := getVolumeSourcePool(spec)
  288. if err != nil {
  289. return nil, err
  290. }
  291. id, err := getVolumeSourceUser(spec)
  292. if err != nil {
  293. return nil, err
  294. }
  295. keyring, err := getVolumeSourceKeyRing(spec)
  296. if err != nil {
  297. return nil, err
  298. }
  299. ro, err := getVolumeSourceReadOnly(spec)
  300. if err != nil {
  301. return nil, err
  302. }
  303. ams, err := getVolumeAccessModes(spec)
  304. if err != nil {
  305. return nil, err
  306. }
  307. return &rbdMounter{
  308. rbd: newRBD(podUID, spec.Name(), img, pool, ro, plugin, manager),
  309. Mon: mon,
  310. Id: id,
  311. Keyring: keyring,
  312. Secret: secret,
  313. fsType: fstype,
  314. mountOptions: volutil.MountOptionFromSpec(spec),
  315. accessModes: ams,
  316. }, nil
  317. }
  318. func (plugin *rbdPlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
  319. // Inject real implementations here, test through the internal function.
  320. return plugin.newUnmounterInternal(volName, podUID, &RBDUtil{})
  321. }
  322. func (plugin *rbdPlugin) newUnmounterInternal(volName string, podUID types.UID, manager diskManager) (volume.Unmounter, error) {
  323. return &rbdUnmounter{
  324. rbdMounter: &rbdMounter{
  325. rbd: newRBD(podUID, volName, "", "", false, plugin, manager),
  326. Mon: make([]string, 0),
  327. },
  328. }, nil
  329. }
  330. func (plugin *rbdPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) {
  331. mounter := plugin.host.GetMounter(plugin.GetPluginName())
  332. pluginMntDir := volutil.GetPluginMountDir(plugin.host, plugin.GetPluginName())
  333. sourceName, err := mounter.GetDeviceNameFromMount(mountPath, pluginMntDir)
  334. if err != nil {
  335. return nil, err
  336. }
  337. s := dstrings.Split(sourceName, "-image-")
  338. if len(s) != 2 {
  339. // The mountPath parameter is the volume mount path for a specific pod, its format
  340. // is /var/lib/kubelet/pods/{podUID}/volumes/{volumePluginName}/{volumeName}.
  341. // mounter.GetDeviceNameFromMount will find the device path(such as /dev/rbd0) by
  342. // mountPath first, and then try to find the global device mount path from the mounted
  343. // path list of this device. sourceName is extracted from this global device mount path.
  344. // mounter.GetDeviceNameFromMount expects the global device mount path conforms to canonical
  345. // format: /var/lib/kubelet/plugins/kubernetes.io/rbd/mounts/{pool}-image-{image}.
  346. // If this assertion failed, it means that the global device mount path is created by
  347. // the deprecated format: /var/lib/kubelet/plugins/kubernetes.io/rbd/rbd/{pool}-image-{image}.
  348. // So we will try to check whether this old style global device mount path exist or not.
  349. // If existed, extract the sourceName from this old style path, otherwise return an error.
  350. klog.V(3).Infof("SourceName %s wrong, fallback to old format", sourceName)
  351. sourceName, err = plugin.getDeviceNameFromOldMountPath(mounter, mountPath)
  352. if err != nil {
  353. return nil, err
  354. }
  355. s = dstrings.Split(sourceName, "-image-")
  356. if len(s) != 2 {
  357. return nil, fmt.Errorf("sourceName %s wrong, should be pool+\"-image-\"+imageName", sourceName)
  358. }
  359. }
  360. rbdVolume := &v1.Volume{
  361. Name: volumeName,
  362. VolumeSource: v1.VolumeSource{
  363. RBD: &v1.RBDVolumeSource{
  364. RBDPool: s[0],
  365. RBDImage: s[1],
  366. },
  367. },
  368. }
  369. return volume.NewSpecFromVolume(rbdVolume), nil
  370. }
  371. func (plugin *rbdPlugin) ConstructBlockVolumeSpec(podUID types.UID, volumeName, mapPath string) (*volume.Spec, error) {
  372. pluginDir := plugin.host.GetVolumeDevicePluginDir(rbdPluginName)
  373. blkutil := volumepathhandler.NewBlockVolumePathHandler()
  374. globalMapPathUUID, err := blkutil.FindGlobalMapPathUUIDFromPod(pluginDir, mapPath, podUID)
  375. if err != nil {
  376. return nil, err
  377. }
  378. klog.V(5).Infof("globalMapPathUUID: %v, err: %v", globalMapPathUUID, err)
  379. globalMapPath := filepath.Dir(globalMapPathUUID)
  380. if len(globalMapPath) == 1 {
  381. return nil, fmt.Errorf("failed to retrieve volume plugin information from globalMapPathUUID: %v", globalMapPathUUID)
  382. }
  383. return getVolumeSpecFromGlobalMapPath(globalMapPath, volumeName)
  384. }
  385. func getVolumeSpecFromGlobalMapPath(globalMapPath, volumeName string) (*volume.Spec, error) {
  386. // Retrieve volume spec information from globalMapPath
  387. // globalMapPath example:
  388. // plugins/kubernetes.io/{PluginName}/{DefaultKubeletVolumeDevicesDirName}/{volumePluginDependentPath}
  389. pool, image, err := getPoolAndImageFromMapPath(globalMapPath)
  390. if err != nil {
  391. return nil, err
  392. }
  393. block := v1.PersistentVolumeBlock
  394. rbdVolume := &v1.PersistentVolume{
  395. ObjectMeta: metav1.ObjectMeta{
  396. Name: volumeName,
  397. },
  398. Spec: v1.PersistentVolumeSpec{
  399. PersistentVolumeSource: v1.PersistentVolumeSource{
  400. RBD: &v1.RBDPersistentVolumeSource{
  401. RBDImage: image,
  402. RBDPool: pool,
  403. },
  404. },
  405. VolumeMode: &block,
  406. },
  407. }
  408. return volume.NewSpecFromPersistentVolume(rbdVolume, true), nil
  409. }
  410. func (plugin *rbdPlugin) NewBlockVolumeMapper(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.BlockVolumeMapper, error) {
  411. var uid types.UID
  412. if pod != nil {
  413. uid = pod.UID
  414. }
  415. secret := ""
  416. if pod != nil {
  417. secretName, secretNs, err := getSecretNameAndNamespace(spec, pod.Namespace)
  418. if err != nil {
  419. return nil, err
  420. }
  421. if len(secretName) > 0 && len(secretNs) > 0 {
  422. // if secret is provideded, retrieve it
  423. kubeClient := plugin.host.GetKubeClient()
  424. if kubeClient == nil {
  425. return nil, fmt.Errorf("Cannot get kube client")
  426. }
  427. secrets, err := kubeClient.CoreV1().Secrets(secretNs).Get(secretName, metav1.GetOptions{})
  428. if err != nil {
  429. err = fmt.Errorf("Couldn't get secret %v/%v err: %v", secretNs, secretName, err)
  430. return nil, err
  431. }
  432. for _, data := range secrets.Data {
  433. secret = string(data)
  434. }
  435. }
  436. }
  437. return plugin.newBlockVolumeMapperInternal(spec, uid, &RBDUtil{}, secret, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName()))
  438. }
  439. func (plugin *rbdPlugin) newBlockVolumeMapperInternal(spec *volume.Spec, podUID types.UID, manager diskManager, secret string, mounter mount.Interface, exec mount.Exec) (volume.BlockVolumeMapper, error) {
  440. mon, err := getVolumeSourceMonitors(spec)
  441. if err != nil {
  442. return nil, err
  443. }
  444. img, err := getVolumeSourceImage(spec)
  445. if err != nil {
  446. return nil, err
  447. }
  448. pool, err := getVolumeSourcePool(spec)
  449. if err != nil {
  450. return nil, err
  451. }
  452. id, err := getVolumeSourceUser(spec)
  453. if err != nil {
  454. return nil, err
  455. }
  456. keyring, err := getVolumeSourceKeyRing(spec)
  457. if err != nil {
  458. return nil, err
  459. }
  460. ro, err := getVolumeSourceReadOnly(spec)
  461. if err != nil {
  462. return nil, err
  463. }
  464. return &rbdDiskMapper{
  465. rbd: newRBD(podUID, spec.Name(), img, pool, ro, plugin, manager),
  466. mon: mon,
  467. id: id,
  468. keyring: keyring,
  469. secret: secret,
  470. }, nil
  471. }
  472. func (plugin *rbdPlugin) NewBlockVolumeUnmapper(volName string, podUID types.UID) (volume.BlockVolumeUnmapper, error) {
  473. return plugin.newUnmapperInternal(volName, podUID, &RBDUtil{})
  474. }
  475. func (plugin *rbdPlugin) newUnmapperInternal(volName string, podUID types.UID, manager diskManager) (volume.BlockVolumeUnmapper, error) {
  476. return &rbdDiskUnmapper{
  477. rbdDiskMapper: &rbdDiskMapper{
  478. rbd: newRBD(podUID, volName, "", "", false, plugin, manager),
  479. mon: make([]string, 0),
  480. },
  481. }, nil
  482. }
  483. func (plugin *rbdPlugin) getDeviceNameFromOldMountPath(mounter mount.Interface, mountPath string) (string, error) {
  484. refs, err := mounter.GetMountRefs(mountPath)
  485. if err != nil {
  486. return "", err
  487. }
  488. // baseMountPath is the prefix of deprecated device global mounted path,
  489. // such as: /var/lib/kubelet/plugins/kubernetes.io/rbd/rbd
  490. baseMountPath := filepath.Join(plugin.host.GetPluginDir(rbdPluginName), "rbd")
  491. for _, ref := range refs {
  492. if dstrings.HasPrefix(ref, baseMountPath) {
  493. return filepath.Rel(baseMountPath, ref)
  494. }
  495. }
  496. return "", fmt.Errorf("can't find source name from mounted path: %s", mountPath)
  497. }
  498. func (plugin *rbdPlugin) NewDeleter(spec *volume.Spec) (volume.Deleter, error) {
  499. if spec.PersistentVolume != nil && spec.PersistentVolume.Spec.RBD == nil {
  500. return nil, fmt.Errorf("spec.PersistentVolume.Spec.RBD is nil")
  501. }
  502. admin, secret, err := plugin.getAdminAndSecret(spec)
  503. if err != nil {
  504. return nil, err
  505. }
  506. return plugin.newDeleterInternal(spec, admin, secret, &RBDUtil{})
  507. }
  508. func (plugin *rbdPlugin) newDeleterInternal(spec *volume.Spec, admin, secret string, manager diskManager) (volume.Deleter, error) {
  509. return &rbdVolumeDeleter{
  510. rbdMounter: &rbdMounter{
  511. rbd: newRBD("", spec.Name(), spec.PersistentVolume.Spec.RBD.RBDImage, spec.PersistentVolume.Spec.RBD.RBDPool, false, plugin, manager),
  512. Mon: spec.PersistentVolume.Spec.RBD.CephMonitors,
  513. adminId: admin,
  514. adminSecret: secret,
  515. }}, nil
  516. }
  517. func (plugin *rbdPlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) {
  518. return plugin.newProvisionerInternal(options, &RBDUtil{})
  519. }
  520. func (plugin *rbdPlugin) newProvisionerInternal(options volume.VolumeOptions, manager diskManager) (volume.Provisioner, error) {
  521. return &rbdVolumeProvisioner{
  522. rbdMounter: &rbdMounter{
  523. rbd: newRBD("", "", "", "", false, plugin, manager),
  524. },
  525. options: options,
  526. }, nil
  527. }
  528. // rbdVolumeProvisioner implements volume.Provisioner interface.
  529. type rbdVolumeProvisioner struct {
  530. *rbdMounter
  531. options volume.VolumeOptions
  532. }
  533. var _ volume.Provisioner = &rbdVolumeProvisioner{}
  534. func (r *rbdVolumeProvisioner) Provision(selectedNode *v1.Node, allowedTopologies []v1.TopologySelectorTerm) (*v1.PersistentVolume, error) {
  535. if !volutil.AccessModesContainedInAll(r.plugin.GetAccessModes(), r.options.PVC.Spec.AccessModes) {
  536. return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", r.options.PVC.Spec.AccessModes, r.plugin.GetAccessModes())
  537. }
  538. if r.options.PVC.Spec.Selector != nil {
  539. return nil, fmt.Errorf("claim Selector is not supported")
  540. }
  541. var err error
  542. adminSecretName := ""
  543. adminSecretNamespace := rbdDefaultAdminSecretNamespace
  544. secret := ""
  545. secretName := ""
  546. secretNamespace := ""
  547. keyring := ""
  548. imageFormat := rbdImageFormat2
  549. fstype := ""
  550. for k, v := range r.options.Parameters {
  551. switch dstrings.ToLower(k) {
  552. case "monitors":
  553. arr := dstrings.Split(v, ",")
  554. r.Mon = append(r.Mon, arr...)
  555. case "adminid":
  556. r.adminId = v
  557. case "adminsecretname":
  558. adminSecretName = v
  559. case "adminsecretnamespace":
  560. adminSecretNamespace = v
  561. case "userid":
  562. r.Id = v
  563. case "pool":
  564. r.Pool = v
  565. case "usersecretname":
  566. secretName = v
  567. case "usersecretnamespace":
  568. secretNamespace = v
  569. case "keyring":
  570. keyring = v
  571. case "imageformat":
  572. imageFormat = v
  573. case "imagefeatures":
  574. arr := dstrings.Split(v, ",")
  575. for _, f := range arr {
  576. if !supportedFeatures.Has(f) {
  577. return nil, fmt.Errorf("invalid feature %q for volume plugin %s, supported features are: %v", f, r.plugin.GetPluginName(), supportedFeatures)
  578. } else {
  579. r.imageFeatures = append(r.imageFeatures, f)
  580. }
  581. }
  582. case volume.VolumeParameterFSType:
  583. fstype = v
  584. default:
  585. return nil, fmt.Errorf("invalid option %q for volume plugin %s", k, r.plugin.GetPluginName())
  586. }
  587. }
  588. // sanity check
  589. if imageFormat != rbdImageFormat1 && imageFormat != rbdImageFormat2 {
  590. return nil, fmt.Errorf("invalid ceph imageformat %s, expecting %s or %s",
  591. imageFormat, rbdImageFormat1, rbdImageFormat2)
  592. }
  593. r.imageFormat = imageFormat
  594. if adminSecretName == "" {
  595. return nil, fmt.Errorf("missing Ceph admin secret name")
  596. }
  597. if secret, err = parsePVSecret(adminSecretNamespace, adminSecretName, r.plugin.host.GetKubeClient()); err != nil {
  598. return nil, fmt.Errorf("failed to get admin secret from [%q/%q]: %v", adminSecretNamespace, adminSecretName, err)
  599. }
  600. r.adminSecret = secret
  601. if len(r.Mon) < 1 {
  602. return nil, fmt.Errorf("missing Ceph monitors")
  603. }
  604. if secretName == "" && keyring == "" {
  605. return nil, fmt.Errorf("must specify either keyring or user secret name")
  606. }
  607. if r.adminId == "" {
  608. r.adminId = rbdDefaultAdminId
  609. }
  610. if r.Pool == "" {
  611. r.Pool = rbdDefaultPool
  612. }
  613. if r.Id == "" {
  614. r.Id = r.adminId
  615. }
  616. // create random image name
  617. image := fmt.Sprintf("kubernetes-dynamic-pvc-%s", uuid.NewUUID())
  618. r.rbdMounter.Image = image
  619. rbd, sizeMB, err := r.manager.CreateImage(r)
  620. if err != nil {
  621. klog.Errorf("rbd: create volume failed, err: %v", err)
  622. return nil, err
  623. }
  624. klog.Infof("successfully created rbd image %q", image)
  625. pv := new(v1.PersistentVolume)
  626. metav1.SetMetaDataAnnotation(&pv.ObjectMeta, volutil.VolumeDynamicallyCreatedByKey, "rbd-dynamic-provisioner")
  627. if secretName != "" {
  628. rbd.SecretRef = new(v1.SecretReference)
  629. rbd.SecretRef.Name = secretName
  630. rbd.SecretRef.Namespace = secretNamespace
  631. } else {
  632. var filePathRegex = regexp.MustCompile(`^(?:/[^/!;` + "`" + ` ]+)+$`)
  633. if keyring != "" && !filePathRegex.MatchString(keyring) {
  634. return nil, fmt.Errorf("keyring field must contain a path to a file")
  635. }
  636. rbd.Keyring = keyring
  637. }
  638. var volumeMode *v1.PersistentVolumeMode
  639. if utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
  640. volumeMode = r.options.PVC.Spec.VolumeMode
  641. if volumeMode != nil && *volumeMode == v1.PersistentVolumeBlock {
  642. // Block volumes should not have any FSType
  643. fstype = ""
  644. }
  645. }
  646. rbd.RadosUser = r.Id
  647. rbd.FSType = fstype
  648. pv.Spec.PersistentVolumeSource.RBD = rbd
  649. pv.Spec.PersistentVolumeReclaimPolicy = r.options.PersistentVolumeReclaimPolicy
  650. pv.Spec.AccessModes = r.options.PVC.Spec.AccessModes
  651. if len(pv.Spec.AccessModes) == 0 {
  652. pv.Spec.AccessModes = r.plugin.GetAccessModes()
  653. }
  654. pv.Spec.Capacity = v1.ResourceList{
  655. v1.ResourceName(v1.ResourceStorage): resource.MustParse(fmt.Sprintf("%dMi", sizeMB)),
  656. }
  657. pv.Spec.MountOptions = r.options.MountOptions
  658. pv.Spec.VolumeMode = volumeMode
  659. return pv, nil
  660. }
  661. // rbdVolumeDeleter implements volume.Deleter interface.
  662. type rbdVolumeDeleter struct {
  663. *rbdMounter
  664. }
  665. var _ volume.Deleter = &rbdVolumeDeleter{}
  666. func (r *rbdVolumeDeleter) GetPath() string {
  667. return getPath(r.podUID, r.volName, r.plugin.host)
  668. }
  669. func (r *rbdVolumeDeleter) Delete() error {
  670. return r.manager.DeleteImage(r)
  671. }
  672. // rbd implmenets volume.Volume interface.
  673. // It's embedded in Mounter/Unmounter/Deleter.
  674. type rbd struct {
  675. volName string
  676. podUID types.UID
  677. Pool string
  678. Image string
  679. ReadOnly bool
  680. plugin *rbdPlugin
  681. mounter *mount.SafeFormatAndMount
  682. exec mount.Exec
  683. // Utility interface that provides API calls to the provider to attach/detach disks.
  684. manager diskManager
  685. volume.MetricsProvider `json:"-"`
  686. }
  687. var _ volume.Volume = &rbd{}
  688. func (rbd *rbd) GetPath() string {
  689. // safe to use PodVolumeDir now: volume teardown occurs before pod is cleaned up
  690. return getPath(rbd.podUID, rbd.volName, rbd.plugin.host)
  691. }
  692. // newRBD creates a new rbd.
  693. func newRBD(podUID types.UID, volName string, image string, pool string, readOnly bool, plugin *rbdPlugin, manager diskManager) *rbd {
  694. return &rbd{
  695. podUID: podUID,
  696. volName: volName,
  697. Image: image,
  698. Pool: pool,
  699. ReadOnly: readOnly,
  700. plugin: plugin,
  701. mounter: volutil.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host),
  702. exec: plugin.host.GetExec(plugin.GetPluginName()),
  703. manager: manager,
  704. MetricsProvider: volume.NewMetricsStatFS(getPath(podUID, volName, plugin.host)),
  705. }
  706. }
  707. // rbdMounter implements volume.Mounter interface.
  708. // It contains information which need to be persisted in whole life cycle of PV
  709. // on the node. It is persisted at the very beginning in the pod mount point
  710. // directory.
  711. // Note: Capitalized field names of this struct determines the information
  712. // persisted on the disk, DO NOT change them. (TODO: refactoring to use a dedicated struct?)
  713. type rbdMounter struct {
  714. *rbd
  715. // capitalized so they can be exported in persistRBD()
  716. Mon []string
  717. Id string
  718. Keyring string
  719. Secret string
  720. fsType string
  721. adminSecret string
  722. adminId string
  723. mountOptions []string
  724. imageFormat string
  725. imageFeatures []string
  726. accessModes []v1.PersistentVolumeAccessMode
  727. }
  728. var _ volume.Mounter = &rbdMounter{}
  729. func (b *rbd) GetAttributes() volume.Attributes {
  730. return volume.Attributes{
  731. ReadOnly: b.ReadOnly,
  732. Managed: !b.ReadOnly,
  733. SupportsSELinux: true,
  734. }
  735. }
  736. // Checks prior to mount operations to verify that the required components (binaries, etc.)
  737. // to mount the volume are available on the underlying node.
  738. // If not, it returns an error
  739. func (b *rbdMounter) CanMount() error {
  740. return nil
  741. }
  742. func (b *rbdMounter) SetUp(mounterArgs volume.MounterArgs) error {
  743. return b.SetUpAt(b.GetPath(), mounterArgs)
  744. }
  745. func (b *rbdMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
  746. // diskSetUp checks mountpoints and prevent repeated calls
  747. klog.V(4).Infof("rbd: attempting to setup at %s", dir)
  748. err := diskSetUp(b.manager, *b, dir, b.mounter, mounterArgs.FsGroup)
  749. if err != nil {
  750. klog.Errorf("rbd: failed to setup at %s %v", dir, err)
  751. }
  752. klog.V(3).Infof("rbd: successfully setup at %s", dir)
  753. return err
  754. }
  755. // rbdUnmounter implements volume.Unmounter interface.
  756. type rbdUnmounter struct {
  757. *rbdMounter
  758. }
  759. var _ volume.Unmounter = &rbdUnmounter{}
  760. // Unmounts the bind mount, and detaches the disk only if the disk
  761. // resource was the last reference to that disk on the kubelet.
  762. func (c *rbdUnmounter) TearDown() error {
  763. return c.TearDownAt(c.GetPath())
  764. }
  765. func (c *rbdUnmounter) TearDownAt(dir string) error {
  766. klog.V(4).Infof("rbd: attempting to teardown at %s", dir)
  767. if pathExists, pathErr := mount.PathExists(dir); pathErr != nil {
  768. return fmt.Errorf("Error checking if path exists: %v", pathErr)
  769. } else if !pathExists {
  770. klog.Warningf("Warning: Unmount skipped because path does not exist: %v", dir)
  771. return nil
  772. }
  773. err := diskTearDown(c.manager, *c, dir, c.mounter)
  774. if err != nil {
  775. return err
  776. }
  777. klog.V(3).Infof("rbd: successfully teardown at %s", dir)
  778. return nil
  779. }
  780. var _ volume.BlockVolumeMapper = &rbdDiskMapper{}
  781. type rbdDiskMapper struct {
  782. *rbd
  783. mon []string
  784. id string
  785. keyring string
  786. secret string
  787. adminSecret string
  788. adminId string
  789. imageFormat string
  790. imageFeatures []string
  791. }
  792. var _ volume.BlockVolumeUnmapper = &rbdDiskUnmapper{}
  793. // GetGlobalMapPath returns global map path and error
  794. // path: plugins/kubernetes.io/{PluginName}/volumeDevices/{rbd pool}-image-{rbd image-name}/{podUid}
  795. func (rbd *rbd) GetGlobalMapPath(spec *volume.Spec) (string, error) {
  796. return rbd.rbdGlobalMapPath(spec)
  797. }
  798. // GetPodDeviceMapPath returns pod device map path and volume name
  799. // path: pods/{podUid}/volumeDevices/kubernetes.io~rbd
  800. // volumeName: pv0001
  801. func (rbd *rbd) GetPodDeviceMapPath() (string, string) {
  802. return rbd.rbdPodDeviceMapPath()
  803. }
  804. func (rbd *rbdDiskMapper) SetUpDevice() (string, error) {
  805. return "", nil
  806. }
  807. func (rbd *rbdDiskMapper) MapDevice(devicePath, globalMapPath, volumeMapPath, volumeMapName string, podUID types.UID) error {
  808. return volutil.MapBlockVolume(devicePath, globalMapPath, volumeMapPath, volumeMapName, podUID)
  809. }
  810. func (rbd *rbd) rbdGlobalMapPath(spec *volume.Spec) (string, error) {
  811. mon, err := getVolumeSourceMonitors(spec)
  812. if err != nil {
  813. return "", err
  814. }
  815. img, err := getVolumeSourceImage(spec)
  816. if err != nil {
  817. return "", err
  818. }
  819. pool, err := getVolumeSourcePool(spec)
  820. if err != nil {
  821. return "", err
  822. }
  823. ro, err := getVolumeSourceReadOnly(spec)
  824. if err != nil {
  825. return "", err
  826. }
  827. mounter := &rbdMounter{
  828. rbd: newRBD("", spec.Name(), img, pool, ro, rbd.plugin, &RBDUtil{}),
  829. Mon: mon,
  830. }
  831. return rbd.manager.MakeGlobalVDPDName(*mounter.rbd), nil
  832. }
  833. func (rbd *rbd) rbdPodDeviceMapPath() (string, string) {
  834. name := rbdPluginName
  835. return rbd.plugin.host.GetPodVolumeDeviceDir(rbd.podUID, utilstrings.EscapeQualifiedName(name)), rbd.volName
  836. }
  837. type rbdDiskUnmapper struct {
  838. *rbdDiskMapper
  839. }
  840. func getPoolAndImageFromMapPath(mapPath string) (string, string, error) {
  841. pathParts := dstrings.Split(mapPath, "/")
  842. if len(pathParts) < 2 {
  843. return "", "", fmt.Errorf("corrupted mapPath")
  844. }
  845. rbdParts := dstrings.Split(pathParts[len(pathParts)-1], "-image-")
  846. if len(rbdParts) < 2 {
  847. return "", "", fmt.Errorf("corrupted mapPath")
  848. }
  849. return string(rbdParts[0]), string(rbdParts[1]), nil
  850. }
  851. func getBlockVolumeDevice(mapPath string) (string, error) {
  852. pool, image, err := getPoolAndImageFromMapPath(mapPath)
  853. if err != nil {
  854. return "", err
  855. }
  856. // Getting full device path
  857. device, found := getDevFromImageAndPool(pool, image)
  858. if !found {
  859. return "", err
  860. }
  861. return device, nil
  862. }
  863. func (rbd *rbdDiskUnmapper) TearDownDevice(mapPath, _ string) error {
  864. device, err := getBlockVolumeDevice(mapPath)
  865. if err != nil {
  866. return fmt.Errorf("rbd: failed to get loopback for device: %v, err: %v", device, err)
  867. }
  868. err = rbd.manager.DetachBlockDisk(*rbd, mapPath)
  869. if err != nil {
  870. return fmt.Errorf("rbd: failed to detach disk: %s\nError: %v", mapPath, err)
  871. }
  872. klog.V(4).Infof("rbd: %q is unmapped, deleting the directory", mapPath)
  873. err = os.RemoveAll(mapPath)
  874. if err != nil {
  875. return fmt.Errorf("rbd: failed to delete the directory: %s\nError: %v", mapPath, err)
  876. }
  877. klog.V(4).Infof("rbd: successfully detached disk: %s", mapPath)
  878. return nil
  879. }
  880. func getVolumeSourceMonitors(spec *volume.Spec) ([]string, error) {
  881. if spec.Volume != nil && spec.Volume.RBD != nil {
  882. return spec.Volume.RBD.CephMonitors, nil
  883. } else if spec.PersistentVolume != nil &&
  884. spec.PersistentVolume.Spec.RBD != nil {
  885. return spec.PersistentVolume.Spec.RBD.CephMonitors, nil
  886. }
  887. return nil, fmt.Errorf("Spec does not reference a RBD volume type")
  888. }
  889. func getVolumeSourceImage(spec *volume.Spec) (string, error) {
  890. if spec.Volume != nil && spec.Volume.RBD != nil {
  891. return spec.Volume.RBD.RBDImage, nil
  892. } else if spec.PersistentVolume != nil &&
  893. spec.PersistentVolume.Spec.RBD != nil {
  894. return spec.PersistentVolume.Spec.RBD.RBDImage, nil
  895. }
  896. return "", fmt.Errorf("Spec does not reference a RBD volume type")
  897. }
  898. func getVolumeSourceFSType(spec *volume.Spec) (string, error) {
  899. if spec.Volume != nil && spec.Volume.RBD != nil {
  900. return spec.Volume.RBD.FSType, nil
  901. } else if spec.PersistentVolume != nil &&
  902. spec.PersistentVolume.Spec.RBD != nil {
  903. return spec.PersistentVolume.Spec.RBD.FSType, nil
  904. }
  905. return "", fmt.Errorf("Spec does not reference a RBD volume type")
  906. }
  907. func getVolumeSourcePool(spec *volume.Spec) (string, error) {
  908. if spec.Volume != nil && spec.Volume.RBD != nil {
  909. return spec.Volume.RBD.RBDPool, nil
  910. } else if spec.PersistentVolume != nil &&
  911. spec.PersistentVolume.Spec.RBD != nil {
  912. return spec.PersistentVolume.Spec.RBD.RBDPool, nil
  913. }
  914. return "", fmt.Errorf("Spec does not reference a RBD volume type")
  915. }
  916. func getVolumeSourceUser(spec *volume.Spec) (string, error) {
  917. if spec.Volume != nil && spec.Volume.RBD != nil {
  918. return spec.Volume.RBD.RadosUser, nil
  919. } else if spec.PersistentVolume != nil &&
  920. spec.PersistentVolume.Spec.RBD != nil {
  921. return spec.PersistentVolume.Spec.RBD.RadosUser, nil
  922. }
  923. return "", fmt.Errorf("Spec does not reference a RBD volume type")
  924. }
  925. func getVolumeSourceKeyRing(spec *volume.Spec) (string, error) {
  926. if spec.Volume != nil && spec.Volume.RBD != nil {
  927. return spec.Volume.RBD.Keyring, nil
  928. } else if spec.PersistentVolume != nil &&
  929. spec.PersistentVolume.Spec.RBD != nil {
  930. return spec.PersistentVolume.Spec.RBD.Keyring, nil
  931. }
  932. return "", fmt.Errorf("Spec does not reference a RBD volume type")
  933. }
  934. func getVolumeSourceReadOnly(spec *volume.Spec) (bool, error) {
  935. if spec.Volume != nil && spec.Volume.RBD != nil {
  936. return spec.Volume.RBD.ReadOnly, nil
  937. } else if spec.PersistentVolume != nil &&
  938. spec.PersistentVolume.Spec.RBD != nil {
  939. // rbd volumes used as a PersistentVolume gets the ReadOnly flag indirectly through
  940. // the persistent-claim volume used to mount the PV
  941. return spec.ReadOnly, nil
  942. }
  943. return false, fmt.Errorf("Spec does not reference a RBD volume type")
  944. }
  945. func getVolumeAccessModes(spec *volume.Spec) ([]v1.PersistentVolumeAccessMode, error) {
  946. // Only PersistentVolumeSpec has AccessModes
  947. if spec.PersistentVolume != nil {
  948. if spec.PersistentVolume.Spec.RBD != nil {
  949. return spec.PersistentVolume.Spec.AccessModes, nil
  950. } else {
  951. return nil, fmt.Errorf("Spec does not reference a RBD volume type")
  952. }
  953. }
  954. return nil, nil
  955. }
  956. func parsePVSecret(namespace, secretName string, kubeClient clientset.Interface) (string, error) {
  957. secret, err := volutil.GetSecretForPV(namespace, secretName, rbdPluginName, kubeClient)
  958. if err != nil {
  959. klog.Errorf("failed to get secret from [%q/%q]: %+v", namespace, secretName, err)
  960. return "", fmt.Errorf("failed to get secret from [%q/%q]: %+v", namespace, secretName, err)
  961. }
  962. return parseSecretMap(secret)
  963. }
  964. // parseSecretMap locates the secret by key name.
  965. func parseSecretMap(secretMap map[string]string) (string, error) {
  966. if len(secretMap) == 0 {
  967. return "", fmt.Errorf("empty secret map")
  968. }
  969. secret := ""
  970. for k, v := range secretMap {
  971. if k == secretKeyName {
  972. return v, nil
  973. }
  974. secret = v
  975. }
  976. // If not found, the last secret in the map wins as done before
  977. return secret, nil
  978. }
  979. func getSecretNameAndNamespace(spec *volume.Spec, defaultNamespace string) (string, string, error) {
  980. if spec.Volume != nil && spec.Volume.RBD != nil {
  981. localSecretRef := spec.Volume.RBD.SecretRef
  982. if localSecretRef != nil {
  983. return localSecretRef.Name, defaultNamespace, nil
  984. }
  985. return "", "", nil
  986. } else if spec.PersistentVolume != nil &&
  987. spec.PersistentVolume.Spec.RBD != nil {
  988. secretRef := spec.PersistentVolume.Spec.RBD.SecretRef
  989. secretNs := defaultNamespace
  990. if secretRef != nil {
  991. if len(secretRef.Namespace) != 0 {
  992. secretNs = secretRef.Namespace
  993. }
  994. return secretRef.Name, secretNs, nil
  995. }
  996. return "", "", nil
  997. }
  998. return "", "", fmt.Errorf("Spec does not reference an RBD volume type")
  999. }