rbd_test.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  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. "reflect"
  19. "runtime"
  20. "strings"
  21. "sync"
  22. "testing"
  23. "time"
  24. "k8s.io/api/core/v1"
  25. "k8s.io/apimachinery/pkg/api/resource"
  26. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  27. "k8s.io/apimachinery/pkg/types"
  28. "k8s.io/apimachinery/pkg/util/uuid"
  29. "k8s.io/client-go/kubernetes/fake"
  30. utiltesting "k8s.io/client-go/util/testing"
  31. "k8s.io/kubernetes/pkg/util/mount"
  32. "k8s.io/kubernetes/pkg/volume"
  33. volumetest "k8s.io/kubernetes/pkg/volume/testing"
  34. )
  35. const (
  36. testVolName = "vol-1234"
  37. testRBDImage = "volume-a4b47414-a675-47dc-a9cc-c223f13439b0"
  38. testRBDPool = "volumes"
  39. testGlobalPath = "plugins/kubernetes.io/rbd/volumeDevices/volumes-image-volume-a4b47414-a675-47dc-a9cc-c223f13439b0"
  40. )
  41. func TestGetVolumeSpecFromGlobalMapPath(t *testing.T) {
  42. // make our test path for fake GlobalMapPath
  43. // /tmp symbolized our pluginDir
  44. // /tmp/testGlobalPathXXXXX/plugins/kubernetes.io/rbd/volumeDevices/pdVol1
  45. tmpVDir, err := utiltesting.MkTmpdir("rbdBlockTest")
  46. if err != nil {
  47. t.Fatalf("can't make a temp dir: %v", err)
  48. }
  49. //deferred clean up
  50. defer os.RemoveAll(tmpVDir)
  51. expectedGlobalPath := filepath.Join(tmpVDir, testGlobalPath)
  52. //Bad Path
  53. badspec, err := getVolumeSpecFromGlobalMapPath("", testVolName)
  54. if badspec != nil || err == nil {
  55. t.Fatalf("Expected not to get spec from GlobalMapPath but did")
  56. }
  57. // Good Path
  58. spec, err := getVolumeSpecFromGlobalMapPath(expectedGlobalPath, testVolName)
  59. if spec == nil || err != nil {
  60. t.Fatalf("Failed to get spec from GlobalMapPath: %v", err)
  61. }
  62. if spec.PersistentVolume.Name != testVolName {
  63. t.Errorf("Invalid spec name for GlobalMapPath spec: %s", spec.PersistentVolume.Name)
  64. }
  65. if spec.PersistentVolume.Spec.RBD.RBDPool != testRBDPool {
  66. t.Errorf("Invalid RBDPool from GlobalMapPath spec: %s", spec.PersistentVolume.Spec.RBD.RBDPool)
  67. }
  68. if spec.PersistentVolume.Spec.RBD.RBDImage != testRBDImage {
  69. t.Errorf("Invalid RBDImage from GlobalMapPath spec: %s", spec.PersistentVolume.Spec.RBD.RBDImage)
  70. }
  71. block := v1.PersistentVolumeBlock
  72. specMode := spec.PersistentVolume.Spec.VolumeMode
  73. if &specMode == nil {
  74. t.Errorf("Invalid volumeMode from GlobalMapPath spec: %v - %v", &specMode, block)
  75. }
  76. if *specMode != block {
  77. t.Errorf("Invalid volumeMode from GlobalMapPath spec: %v - %v", *specMode, block)
  78. }
  79. }
  80. func TestCanSupport(t *testing.T) {
  81. tmpDir, err := utiltesting.MkTmpdir("rbd_test")
  82. if err != nil {
  83. t.Fatalf("error creating temp dir: %v", err)
  84. }
  85. defer os.RemoveAll(tmpDir)
  86. plugMgr := volume.VolumePluginMgr{}
  87. plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
  88. plug, err := plugMgr.FindPluginByName("kubernetes.io/rbd")
  89. if err != nil {
  90. t.Errorf("Can't find the plugin by name")
  91. }
  92. if plug.GetPluginName() != "kubernetes.io/rbd" {
  93. t.Errorf("Wrong name: %s", plug.GetPluginName())
  94. }
  95. if plug.CanSupport(&volume.Spec{}) {
  96. t.Errorf("Expected false")
  97. }
  98. if plug.CanSupport(&volume.Spec{Volume: &v1.Volume{VolumeSource: v1.VolumeSource{}}}) {
  99. t.Errorf("Expected false")
  100. }
  101. if !plug.CanSupport(&volume.Spec{Volume: &v1.Volume{VolumeSource: v1.VolumeSource{RBD: &v1.RBDVolumeSource{}}}}) {
  102. t.Errorf("Expected true")
  103. }
  104. if plug.CanSupport(&volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{}}}) {
  105. t.Errorf("Expected false")
  106. }
  107. if plug.CanSupport(&volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{}}}}) {
  108. t.Errorf("Expected false")
  109. }
  110. if !plug.CanSupport(&volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{RBD: &v1.RBDPersistentVolumeSource{}}}}}) {
  111. t.Errorf("Expected true")
  112. }
  113. }
  114. type fakeDiskManager struct {
  115. // Make sure we can run tests in parallel.
  116. mutex sync.RWMutex
  117. // Key format: "<pool>/<image>"
  118. rbdImageLocks map[string]bool
  119. rbdMapIndex int
  120. rbdDevices map[string]bool
  121. }
  122. func NewFakeDiskManager() *fakeDiskManager {
  123. return &fakeDiskManager{
  124. rbdImageLocks: make(map[string]bool),
  125. rbdMapIndex: 0,
  126. rbdDevices: make(map[string]bool),
  127. }
  128. }
  129. func (fake *fakeDiskManager) MakeGlobalPDName(rbd rbd) string {
  130. return makePDNameInternal(rbd.plugin.host, rbd.Pool, rbd.Image)
  131. }
  132. func (fake *fakeDiskManager) MakeGlobalVDPDName(rbd rbd) string {
  133. return makePDNameInternal(rbd.plugin.host, rbd.Pool, rbd.Image)
  134. }
  135. func (fake *fakeDiskManager) AttachDisk(b rbdMounter) (string, error) {
  136. fake.mutex.Lock()
  137. defer fake.mutex.Unlock()
  138. fake.rbdMapIndex++
  139. devicePath := fmt.Sprintf("/dev/rbd%d", fake.rbdMapIndex)
  140. fake.rbdDevices[devicePath] = true
  141. return devicePath, nil
  142. }
  143. func (fake *fakeDiskManager) DetachDisk(r *rbdPlugin, deviceMountPath string, device string) error {
  144. fake.mutex.Lock()
  145. defer fake.mutex.Unlock()
  146. ok := fake.rbdDevices[device]
  147. if !ok {
  148. return fmt.Errorf("rbd: failed to detach device %s, it does not exist", device)
  149. }
  150. delete(fake.rbdDevices, device)
  151. return nil
  152. }
  153. func (fake *fakeDiskManager) DetachBlockDisk(r rbdDiskUnmapper, device string) error {
  154. fake.mutex.Lock()
  155. defer fake.mutex.Unlock()
  156. ok := fake.rbdDevices[device]
  157. if !ok {
  158. return fmt.Errorf("rbd: failed to detach device %s, it does not exist", device)
  159. }
  160. delete(fake.rbdDevices, device)
  161. return nil
  162. }
  163. func (fake *fakeDiskManager) CreateImage(provisioner *rbdVolumeProvisioner) (r *v1.RBDPersistentVolumeSource, volumeSizeGB int, err error) {
  164. return nil, 0, fmt.Errorf("not implemented")
  165. }
  166. func (fake *fakeDiskManager) DeleteImage(deleter *rbdVolumeDeleter) error {
  167. return fmt.Errorf("not implemented")
  168. }
  169. func (fake *fakeDiskManager) Fencing(r rbdMounter, nodeName string) error {
  170. fake.mutex.Lock()
  171. defer fake.mutex.Unlock()
  172. key := fmt.Sprintf("%s/%s", r.Pool, r.Image)
  173. isLocked, ok := fake.rbdImageLocks[key]
  174. if ok && isLocked {
  175. // not expected in testing
  176. return fmt.Errorf("%s is already locked", key)
  177. }
  178. fake.rbdImageLocks[key] = true
  179. return nil
  180. }
  181. func (fake *fakeDiskManager) Defencing(r rbdMounter, nodeName string) error {
  182. fake.mutex.Lock()
  183. defer fake.mutex.Unlock()
  184. key := fmt.Sprintf("%s/%s", r.Pool, r.Image)
  185. isLocked, ok := fake.rbdImageLocks[key]
  186. if !ok || !isLocked {
  187. // not expected in testing
  188. return fmt.Errorf("%s is not locked", key)
  189. }
  190. delete(fake.rbdImageLocks, key)
  191. return nil
  192. }
  193. func (fake *fakeDiskManager) IsLocked(r rbdMounter, nodeName string) (bool, error) {
  194. fake.mutex.RLock()
  195. defer fake.mutex.RUnlock()
  196. key := fmt.Sprintf("%s/%s", r.Pool, r.Image)
  197. isLocked, ok := fake.rbdImageLocks[key]
  198. return ok && isLocked, nil
  199. }
  200. func (fake *fakeDiskManager) ExpandImage(rbdExpander *rbdVolumeExpander, oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error) {
  201. return resource.Quantity{}, fmt.Errorf("not implemented")
  202. }
  203. // checkMounterLog checks fakeMounter must have expected logs, and the last action msut equal to expectedAction.
  204. func checkMounterLog(t *testing.T, fakeMounter *mount.FakeMounter, expected int, expectedAction mount.FakeAction) {
  205. if len(fakeMounter.Log) != expected {
  206. t.Fatalf("fakeMounter should have %d logs, actual: %d", expected, len(fakeMounter.Log))
  207. }
  208. lastIndex := len(fakeMounter.Log) - 1
  209. lastAction := fakeMounter.Log[lastIndex]
  210. if !reflect.DeepEqual(expectedAction, lastAction) {
  211. t.Fatalf("fakeMounter.Log[%d] should be %#v, not: %#v", lastIndex, expectedAction, lastAction)
  212. }
  213. }
  214. func doTestPlugin(t *testing.T, c *testcase) {
  215. fakeVolumeHost := volumetest.NewFakeVolumeHost(c.root, nil, nil)
  216. plugMgr := volume.VolumePluginMgr{}
  217. plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, fakeVolumeHost)
  218. plug, err := plugMgr.FindPluginByName("kubernetes.io/rbd")
  219. if err != nil {
  220. t.Errorf("Can't find the plugin by name")
  221. }
  222. fakeMounter := fakeVolumeHost.GetMounter(plug.GetPluginName()).(*mount.FakeMounter)
  223. fakeNodeName := types.NodeName("localhost")
  224. fdm := NewFakeDiskManager()
  225. // attacher
  226. attacher, err := plug.(*rbdPlugin).newAttacherInternal(fdm)
  227. if err != nil {
  228. t.Errorf("Failed to make a new Attacher: %v", err)
  229. }
  230. deviceAttachPath, err := attacher.Attach(c.spec, fakeNodeName)
  231. if err != nil {
  232. t.Fatal(err)
  233. }
  234. devicePath, err := attacher.WaitForAttach(c.spec, deviceAttachPath, c.pod, time.Second*10)
  235. if err != nil {
  236. t.Fatal(err)
  237. }
  238. if devicePath != c.expectedDevicePath {
  239. t.Errorf("Unexpected path, expected %q, not: %q", c.expectedDevicePath, devicePath)
  240. }
  241. deviceMountPath, err := attacher.GetDeviceMountPath(c.spec)
  242. if err != nil {
  243. t.Fatal(err)
  244. }
  245. if deviceMountPath != c.expectedDeviceMountPath {
  246. t.Errorf("Unexpected mount path, expected %q, not: %q", c.expectedDeviceMountPath, deviceMountPath)
  247. }
  248. err = attacher.MountDevice(c.spec, devicePath, deviceMountPath)
  249. if err != nil {
  250. t.Fatal(err)
  251. }
  252. if _, err := os.Stat(deviceMountPath); err != nil {
  253. if os.IsNotExist(err) {
  254. t.Errorf("Attacher.MountDevice() failed, device mount path not created: %s", deviceMountPath)
  255. } else {
  256. t.Errorf("Attacher.MountDevice() failed: %v", err)
  257. }
  258. }
  259. checkMounterLog(t, fakeMounter, 1, mount.FakeAction{Action: "mount", Target: c.expectedDeviceMountPath, Source: devicePath, FSType: "ext4"})
  260. // mounter
  261. mounter, err := plug.(*rbdPlugin).newMounterInternal(c.spec, c.pod.UID, fdm, "secrets")
  262. if err != nil {
  263. t.Errorf("Failed to make a new Mounter: %v", err)
  264. }
  265. if mounter == nil {
  266. t.Error("Got a nil Mounter")
  267. }
  268. path := mounter.GetPath()
  269. if path != c.expectedPodMountPath {
  270. t.Errorf("Unexpected path, expected %q, got: %q", c.expectedPodMountPath, path)
  271. }
  272. if err := mounter.SetUp(volume.MounterArgs{}); err != nil {
  273. t.Errorf("Expected success, got: %v", err)
  274. }
  275. if _, err := os.Stat(path); err != nil {
  276. if os.IsNotExist(err) {
  277. t.Errorf("SetUp() failed, volume path not created: %s", path)
  278. } else {
  279. t.Errorf("SetUp() failed: %v", err)
  280. }
  281. }
  282. checkMounterLog(t, fakeMounter, 2, mount.FakeAction{Action: "mount", Target: c.expectedPodMountPath, Source: devicePath, FSType: ""})
  283. // unmounter
  284. unmounter, err := plug.(*rbdPlugin).newUnmounterInternal(c.spec.Name(), c.pod.UID, fdm)
  285. if err != nil {
  286. t.Errorf("Failed to make a new Unmounter: %v", err)
  287. }
  288. if unmounter == nil {
  289. t.Error("Got a nil Unmounter")
  290. }
  291. if err := unmounter.TearDown(); err != nil {
  292. t.Errorf("Expected success, got: %v", err)
  293. }
  294. if _, err := os.Stat(path); err == nil {
  295. t.Errorf("TearDown() failed, volume path still exists: %s", path)
  296. } else if !os.IsNotExist(err) {
  297. t.Errorf("TearDown() failed: %v", err)
  298. }
  299. checkMounterLog(t, fakeMounter, 3, mount.FakeAction{Action: "unmount", Target: c.expectedPodMountPath, Source: "", FSType: ""})
  300. // detacher
  301. detacher, err := plug.(*rbdPlugin).newDetacherInternal(fdm)
  302. if err != nil {
  303. t.Errorf("Failed to make a new Attacher: %v", err)
  304. }
  305. err = detacher.UnmountDevice(deviceMountPath)
  306. if err != nil {
  307. t.Fatalf("Detacher.UnmountDevice failed to unmount %s", deviceMountPath)
  308. }
  309. checkMounterLog(t, fakeMounter, 4, mount.FakeAction{Action: "unmount", Target: c.expectedDeviceMountPath, Source: "", FSType: ""})
  310. err = detacher.Detach(deviceMountPath, fakeNodeName)
  311. if err != nil {
  312. t.Fatalf("Detacher.Detach failed to detach %s from %s", deviceMountPath, fakeNodeName)
  313. }
  314. }
  315. type testcase struct {
  316. spec *volume.Spec
  317. root string
  318. pod *v1.Pod
  319. expectedDevicePath string
  320. expectedDeviceMountPath string
  321. expectedPodMountPath string
  322. }
  323. func TestPlugin(t *testing.T) {
  324. tmpDir, err := utiltesting.MkTmpdir("rbd_test")
  325. if err != nil {
  326. t.Fatalf("error creating temp dir: %v", err)
  327. }
  328. defer os.RemoveAll(tmpDir)
  329. tmpDir, err = filepath.EvalSymlinks(tmpDir)
  330. if err != nil {
  331. t.Fatal(err)
  332. }
  333. podUID := uuid.NewUUID()
  334. var cases []*testcase
  335. cases = append(cases, &testcase{
  336. spec: volume.NewSpecFromVolume(&v1.Volume{
  337. Name: "vol1",
  338. VolumeSource: v1.VolumeSource{
  339. RBD: &v1.RBDVolumeSource{
  340. CephMonitors: []string{"a", "b"},
  341. RBDPool: "pool1",
  342. RBDImage: "image1",
  343. FSType: "ext4",
  344. ReadOnly: true,
  345. },
  346. },
  347. }),
  348. root: tmpDir,
  349. pod: &v1.Pod{
  350. ObjectMeta: metav1.ObjectMeta{
  351. Name: "testpod",
  352. Namespace: "testns",
  353. UID: podUID,
  354. },
  355. },
  356. expectedDevicePath: "/dev/rbd1",
  357. expectedDeviceMountPath: fmt.Sprintf("%s/plugins/kubernetes.io/rbd/mounts/pool1-image-image1", tmpDir),
  358. expectedPodMountPath: fmt.Sprintf("%s/pods/%s/volumes/kubernetes.io~rbd/vol1", tmpDir, podUID),
  359. })
  360. cases = append(cases, &testcase{
  361. spec: volume.NewSpecFromPersistentVolume(&v1.PersistentVolume{
  362. ObjectMeta: metav1.ObjectMeta{
  363. Name: "vol2",
  364. },
  365. Spec: v1.PersistentVolumeSpec{
  366. PersistentVolumeSource: v1.PersistentVolumeSource{
  367. RBD: &v1.RBDPersistentVolumeSource{
  368. CephMonitors: []string{"a", "b"},
  369. RBDPool: "pool2",
  370. RBDImage: "image2",
  371. FSType: "ext4",
  372. },
  373. },
  374. AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadOnlyMany},
  375. },
  376. }, false),
  377. root: tmpDir,
  378. pod: &v1.Pod{
  379. ObjectMeta: metav1.ObjectMeta{
  380. Name: "testpod",
  381. Namespace: "testns",
  382. UID: podUID,
  383. },
  384. },
  385. expectedDevicePath: "/dev/rbd1",
  386. expectedDeviceMountPath: fmt.Sprintf("%s/plugins/kubernetes.io/rbd/mounts/pool2-image-image2", tmpDir),
  387. expectedPodMountPath: fmt.Sprintf("%s/pods/%s/volumes/kubernetes.io~rbd/vol2", tmpDir, podUID),
  388. })
  389. for i := 0; i < len(cases); i++ {
  390. doTestPlugin(t, cases[i])
  391. }
  392. }
  393. func TestPersistentClaimReadOnlyFlag(t *testing.T) {
  394. tmpDir, err := utiltesting.MkTmpdir("rbd_test")
  395. if err != nil {
  396. t.Fatalf("error creating temp dir: %v", err)
  397. }
  398. defer os.RemoveAll(tmpDir)
  399. pv := &v1.PersistentVolume{
  400. ObjectMeta: metav1.ObjectMeta{
  401. Name: "pvA",
  402. },
  403. Spec: v1.PersistentVolumeSpec{
  404. PersistentVolumeSource: v1.PersistentVolumeSource{
  405. RBD: &v1.RBDPersistentVolumeSource{
  406. CephMonitors: []string{"a", "b"},
  407. RBDImage: "bar",
  408. FSType: "ext4",
  409. },
  410. },
  411. ClaimRef: &v1.ObjectReference{
  412. Name: "claimA",
  413. },
  414. },
  415. }
  416. claim := &v1.PersistentVolumeClaim{
  417. ObjectMeta: metav1.ObjectMeta{
  418. Name: "claimA",
  419. Namespace: "nsA",
  420. },
  421. Spec: v1.PersistentVolumeClaimSpec{
  422. VolumeName: "pvA",
  423. },
  424. Status: v1.PersistentVolumeClaimStatus{
  425. Phase: v1.ClaimBound,
  426. },
  427. }
  428. client := fake.NewSimpleClientset(pv, claim)
  429. plugMgr := volume.VolumePluginMgr{}
  430. plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, client, nil))
  431. plug, _ := plugMgr.FindPluginByName(rbdPluginName)
  432. // readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes
  433. spec := volume.NewSpecFromPersistentVolume(pv, true)
  434. pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: types.UID("poduid")}}
  435. mounter, _ := plug.NewMounter(spec, pod, volume.VolumeOptions{})
  436. if mounter == nil {
  437. t.Fatalf("Got a nil Mounter")
  438. }
  439. if !mounter.GetAttributes().ReadOnly {
  440. t.Errorf("Expected true for mounter.IsReadOnly")
  441. }
  442. }
  443. func TestGetSecretNameAndNamespace(t *testing.T) {
  444. secretName := "test-secret-name"
  445. secretNamespace := "test-secret-namespace"
  446. volSpec := &volume.Spec{
  447. PersistentVolume: &v1.PersistentVolume{
  448. Spec: v1.PersistentVolumeSpec{
  449. PersistentVolumeSource: v1.PersistentVolumeSource{
  450. RBD: &v1.RBDPersistentVolumeSource{
  451. CephMonitors: []string{"a", "b"},
  452. RBDImage: "bar",
  453. FSType: "ext4",
  454. },
  455. },
  456. },
  457. },
  458. }
  459. secretRef := new(v1.SecretReference)
  460. secretRef.Name = secretName
  461. secretRef.Namespace = secretNamespace
  462. volSpec.PersistentVolume.Spec.PersistentVolumeSource.RBD.SecretRef = secretRef
  463. foundSecretName, foundSecretNamespace, err := getSecretNameAndNamespace(volSpec, "default")
  464. if err != nil {
  465. t.Errorf("getSecretNameAndNamespace failed to get Secret's name and namespace: %v", err)
  466. }
  467. if strings.Compare(secretName, foundSecretName) != 0 || strings.Compare(secretNamespace, foundSecretNamespace) != 0 {
  468. t.Errorf("getSecretNameAndNamespace returned incorrect values, expected %s and %s but got %s and %s", secretName, secretNamespace, foundSecretName, foundSecretNamespace)
  469. }
  470. }
  471. // https://github.com/kubernetes/kubernetes/issues/57744
  472. func TestGetDeviceMountPath(t *testing.T) {
  473. tmpDir, err := utiltesting.MkTmpdir("rbd_test")
  474. if err != nil {
  475. t.Fatalf("error creating temp dir: %v", err)
  476. }
  477. defer os.RemoveAll(tmpDir)
  478. fakeVolumeHost := volumetest.NewFakeVolumeHost(tmpDir, nil, nil)
  479. plugMgr := volume.VolumePluginMgr{}
  480. plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, fakeVolumeHost)
  481. plug, err := plugMgr.FindPluginByName("kubernetes.io/rbd")
  482. if err != nil {
  483. t.Errorf("Can't find the plugin by name")
  484. }
  485. fdm := NewFakeDiskManager()
  486. // attacher
  487. attacher, err := plug.(*rbdPlugin).newAttacherInternal(fdm)
  488. if err != nil {
  489. t.Errorf("Failed to make a new Attacher: %v", err)
  490. }
  491. pool, image := "pool", "image"
  492. spec := volume.NewSpecFromVolume(&v1.Volume{
  493. Name: "vol",
  494. VolumeSource: v1.VolumeSource{
  495. RBD: &v1.RBDVolumeSource{
  496. CephMonitors: []string{"a", "b"},
  497. RBDPool: pool,
  498. RBDImage: image,
  499. FSType: "ext4",
  500. },
  501. },
  502. })
  503. deprecatedDir := fmt.Sprintf("%s/plugins/kubernetes.io/rbd/rbd/%s-image-%s", tmpDir, pool, image)
  504. canonicalDir := fmt.Sprintf("%s/plugins/kubernetes.io/rbd/mounts/%s-image-%s", tmpDir, pool, image)
  505. type testCase struct {
  506. deprecated bool
  507. targetPath string
  508. }
  509. for _, c := range []testCase{
  510. {false, canonicalDir},
  511. {true, deprecatedDir},
  512. } {
  513. if c.deprecated {
  514. // This is a deprecated device mount path, we create it,
  515. // and hope attacher.GetDeviceMountPath return c.targetPath.
  516. if err := os.MkdirAll(c.targetPath, 0700); err != nil {
  517. t.Fatalf("Create deprecated mount path failed: %v", err)
  518. }
  519. }
  520. mountPath, err := attacher.GetDeviceMountPath(spec)
  521. if err != nil {
  522. t.Fatalf("GetDeviceMountPath failed: %v", err)
  523. }
  524. if mountPath != c.targetPath {
  525. t.Errorf("Mismatch device mount path: wanted %s, got %s", c.targetPath, mountPath)
  526. }
  527. }
  528. }
  529. // https://github.com/kubernetes/kubernetes/issues/57744
  530. func TestConstructVolumeSpec(t *testing.T) {
  531. if runtime.GOOS == "darwin" {
  532. t.Skipf("TestConstructVolumeSpec is not supported on GOOS=%s", runtime.GOOS)
  533. }
  534. tmpDir, err := utiltesting.MkTmpdir("rbd_test")
  535. if err != nil {
  536. t.Fatalf("error creating temp dir: %v", err)
  537. }
  538. defer os.RemoveAll(tmpDir)
  539. fakeVolumeHost := volumetest.NewFakeVolumeHost(tmpDir, nil, nil)
  540. plugMgr := volume.VolumePluginMgr{}
  541. plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, fakeVolumeHost)
  542. plug, err := plugMgr.FindPluginByName("kubernetes.io/rbd")
  543. if err != nil {
  544. t.Errorf("Can't find the plugin by name")
  545. }
  546. fakeMounter := fakeVolumeHost.GetMounter(plug.GetPluginName()).(*mount.FakeMounter)
  547. pool, image, volumeName := "pool", "image", "vol"
  548. podMountPath := fmt.Sprintf("%s/pods/pod123/volumes/kubernetes.io~rbd/%s", tmpDir, volumeName)
  549. deprecatedDir := fmt.Sprintf("%s/plugins/kubernetes.io/rbd/rbd/%s-image-%s", tmpDir, pool, image)
  550. canonicalDir := fmt.Sprintf("%s/plugins/kubernetes.io/rbd/mounts/%s-image-%s", tmpDir, pool, image)
  551. type testCase struct {
  552. volumeName string
  553. targetPath string
  554. }
  555. for _, c := range []testCase{
  556. {"vol", canonicalDir},
  557. {"vol", deprecatedDir},
  558. } {
  559. if err := os.MkdirAll(c.targetPath, 0700); err != nil {
  560. t.Fatalf("Create mount path %s failed: %v", c.targetPath, err)
  561. }
  562. if err = fakeMounter.Mount("/dev/rbd0", c.targetPath, "fake", nil); err != nil {
  563. t.Fatalf("Mount %s to %s failed: %v", c.targetPath, podMountPath, err)
  564. }
  565. if err = fakeMounter.Mount(c.targetPath, podMountPath, "fake", []string{"bind"}); err != nil {
  566. t.Fatalf("Mount %s to %s failed: %v", c.targetPath, podMountPath, err)
  567. }
  568. spec, err := plug.ConstructVolumeSpec(c.volumeName, podMountPath)
  569. if err != nil {
  570. t.Errorf("ConstructVolumeSpec failed: %v", err)
  571. } else {
  572. if spec.Volume.RBD.RBDPool != pool {
  573. t.Errorf("Mismatch rbd pool: wanted %s, got %s", pool, spec.Volume.RBD.RBDPool)
  574. }
  575. if spec.Volume.RBD.RBDImage != image {
  576. t.Fatalf("Mismatch rbd image: wanted %s, got %s", image, spec.Volume.RBD.RBDImage)
  577. }
  578. }
  579. if err = fakeMounter.Unmount(podMountPath); err != nil {
  580. t.Fatalf("Unmount pod path %s failed: %v", podMountPath, err)
  581. }
  582. if err = fakeMounter.Unmount(c.targetPath); err != nil {
  583. t.Fatalf("Unmount device path %s failed: %v", c.targetPath, err)
  584. }
  585. }
  586. }
  587. func TestGetAccessModes(t *testing.T) {
  588. tmpDir, err := utiltesting.MkTmpdir("rbd_test")
  589. if err != nil {
  590. t.Fatalf("error creating temp dir: %v", err)
  591. }
  592. defer os.RemoveAll(tmpDir)
  593. plugMgr := volume.VolumePluginMgr{}
  594. plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
  595. plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/rbd")
  596. if err != nil {
  597. t.Errorf("Can't find the plugin by name")
  598. }
  599. modes := plug.GetAccessModes()
  600. for _, v := range modes {
  601. if !volumetest.ContainsAccessMode(modes, v) {
  602. t.Errorf("Expected AccessModeTypes: %s", v)
  603. }
  604. }
  605. }
  606. func TestRequiresRemount(t *testing.T) {
  607. tmpDir, _ := utiltesting.MkTmpdir("rbd_test")
  608. plugMgr := volume.VolumePluginMgr{}
  609. plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(tmpDir, nil, nil))
  610. plug, _ := plugMgr.FindPluginByName("kubernetes.io/rbd")
  611. has := plug.RequiresRemount()
  612. if has {
  613. t.Errorf("Exepcted RequiresRemount to be false, got %t", has)
  614. }
  615. }
  616. func TestGetRbdImageSize(t *testing.T) {
  617. for i, c := range []struct {
  618. Output string
  619. TargetSize int
  620. }{
  621. {
  622. Output: `{"name":"kubernetes-dynamic-pvc-18e7a4d9-050d-11e9-b905-548998f3478f","size":10737418240,"objects":2560,"order":22,"object_size":4194304,"block_name_prefix":"rbd_data.9f4ff7238e1f29","format":2}`,
  623. TargetSize: 10240,
  624. },
  625. {
  626. Output: `{"name":"kubernetes-dynamic-pvc-070635bf-e33f-11e8-aab7-548998f3478f","size":1073741824,"objects":256,"order":22,"object_size":4194304,"block_name_prefix":"rbd_data.670ac4238e1f29","format":2}`,
  627. TargetSize: 1024,
  628. },
  629. } {
  630. size, err := getRbdImageSize([]byte(c.Output))
  631. if err != nil {
  632. t.Errorf("Case %d: getRbdImageSize failed: %v", i, err)
  633. continue
  634. }
  635. if size != c.TargetSize {
  636. t.Errorf("Case %d: unexpected size, wanted %d, got %d", i, c.TargetSize, size)
  637. }
  638. }
  639. }