persistent_volumes.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  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 e2e
  14. import (
  15. "encoding/json"
  16. "fmt"
  17. "time"
  18. . "github.com/onsi/ginkgo"
  19. "k8s.io/kubernetes/pkg/api"
  20. apierrs "k8s.io/kubernetes/pkg/api/errors"
  21. "k8s.io/kubernetes/pkg/api/resource"
  22. "k8s.io/kubernetes/pkg/api/testapi"
  23. "k8s.io/kubernetes/pkg/api/unversioned"
  24. client "k8s.io/kubernetes/pkg/client/unversioned"
  25. "k8s.io/kubernetes/pkg/volume/util/volumehelper"
  26. "k8s.io/kubernetes/test/e2e/framework"
  27. )
  28. // Delete the nfs-server pod.
  29. func nfsServerPodCleanup(c *client.Client, config VolumeTestConfig) {
  30. defer GinkgoRecover()
  31. podClient := c.Pods(config.namespace)
  32. if config.serverImage != "" {
  33. podName := config.prefix + "-server"
  34. err := podClient.Delete(podName, nil)
  35. if err != nil {
  36. framework.Logf("Delete of %v pod failed: %v", podName, err)
  37. }
  38. }
  39. }
  40. // Delete the PV. Fail test if delete fails. If success the returned PV should
  41. // be nil, which prevents the AfterEach from attempting to delete it.
  42. func deletePersistentVolume(c *client.Client, pv *api.PersistentVolume) (*api.PersistentVolume, error) {
  43. if pv == nil {
  44. return nil, fmt.Errorf("PV to be deleted is nil")
  45. }
  46. framework.Logf("Deleting PersistentVolume %v", pv.Name)
  47. err := c.PersistentVolumes().Delete(pv.Name)
  48. if err != nil {
  49. return pv, fmt.Errorf("Delete() PersistentVolume %v failed: %v", pv.Name, err)
  50. }
  51. // Wait for PersistentVolume to delete
  52. deleteDuration := 90 * time.Second
  53. err = framework.WaitForPersistentVolumeDeleted(c, pv.Name, 3*time.Second, deleteDuration)
  54. if err != nil {
  55. return pv, fmt.Errorf("Unable to delete PersistentVolume %s after waiting for %v: %v", pv.Name, deleteDuration, err)
  56. }
  57. return nil, nil // success
  58. }
  59. // Delete the PVC and wait for the PV to become Available again. Validate that
  60. // the PV has recycled (assumption here about reclaimPolicy). Return the pv and
  61. // pvc to reflect that these resources have been retrieved again (Get). If the
  62. // delete is successful the returned pvc should be nil and the pv non-nil.
  63. // Note: the pv and pvc are returned back to the It() caller so that the
  64. // AfterEach func can delete these objects if they are not nil.
  65. func deletePVCandValidatePV(c *client.Client, ns string, pvc *api.PersistentVolumeClaim, pv *api.PersistentVolume) (*api.PersistentVolume, *api.PersistentVolumeClaim, error) {
  66. framework.Logf("Deleting PersistentVolumeClaim %v to trigger PV Recycling", pvc.Name)
  67. err := c.PersistentVolumeClaims(ns).Delete(pvc.Name)
  68. if err != nil {
  69. return pv, pvc, fmt.Errorf("Delete of PVC %v failed: %v", pvc.Name, err)
  70. }
  71. // Check that the PVC is really deleted.
  72. pvc, err = c.PersistentVolumeClaims(ns).Get(pvc.Name)
  73. if err == nil {
  74. return pv, pvc, fmt.Errorf("PVC %v deleted yet still exists", pvc.Name)
  75. }
  76. if !apierrs.IsNotFound(err) {
  77. return pv, pvc, fmt.Errorf("Get on deleted PVC %v failed with error other than \"not found\": %v", pvc.Name, err)
  78. }
  79. // Wait for the PV's phase to return to Available
  80. framework.Logf("Waiting for recycling process to complete.")
  81. err = framework.WaitForPersistentVolumePhase(api.VolumeAvailable, c, pv.Name, 3*time.Second, 300*time.Second)
  82. if err != nil {
  83. return pv, pvc, fmt.Errorf("Recycling failed: %v", err)
  84. }
  85. // Examine the pv.ClaimRef and UID. Expect nil values.
  86. pv, err = c.PersistentVolumes().Get(pv.Name)
  87. if err != nil {
  88. return pv, pvc, fmt.Errorf("Cannot re-get PersistentVolume %v:", pv.Name)
  89. }
  90. if pv.Spec.ClaimRef != nil && len(pv.Spec.ClaimRef.UID) > 0 {
  91. crJSON, _ := json.Marshal(pv.Spec.ClaimRef)
  92. return pv, pvc, fmt.Errorf("Expected PV %v's ClaimRef to be nil, or the claimRef's UID to be blank. Instead claimRef is: %v", pv.Name, string(crJSON))
  93. }
  94. return pv, pvc, nil
  95. }
  96. // create the PV resource. Fails test on error.
  97. func createPV(c *client.Client, pv *api.PersistentVolume) (*api.PersistentVolume, error) {
  98. pv, err := c.PersistentVolumes().Create(pv)
  99. if err != nil {
  100. return pv, fmt.Errorf("Create PersistentVolume %v failed: %v", pv.Name, err)
  101. }
  102. return pv, nil
  103. }
  104. // create the PVC resource. Fails test on error.
  105. func createPVC(c *client.Client, ns string, pvc *api.PersistentVolumeClaim) (*api.PersistentVolumeClaim, error) {
  106. pvc, err := c.PersistentVolumeClaims(ns).Create(pvc)
  107. if err != nil {
  108. return pvc, fmt.Errorf("Create PersistentVolumeClaim %v failed: %v", pvc.Name, err)
  109. }
  110. return pvc, nil
  111. }
  112. // Create a PVC followed by the PV based on the passed in nfs-server ip and
  113. // namespace. If the "preBind" bool is true then pre-bind the PV to the PVC
  114. // via the PV's ClaimRef. Return the pv and pvc to reflect the created objects.
  115. // Note: the pv and pvc are returned back to the It() caller so that the
  116. // AfterEach func can delete these objects if they are not nil.
  117. // Note: in the pre-bind case the real PVC name, which is generated, is not
  118. // known until after the PVC is instantiated. This is why the pvc is created
  119. // before the pv.
  120. func createPVCPV(c *client.Client, serverIP, ns string, preBind bool) (*api.PersistentVolume, *api.PersistentVolumeClaim, error) {
  121. var bindTo *api.PersistentVolumeClaim
  122. var preBindMsg string
  123. // make the pvc definition first
  124. pvc := makePersistentVolumeClaim(ns)
  125. if preBind {
  126. preBindMsg = " pre-bound"
  127. bindTo = pvc
  128. }
  129. // make the pv spec
  130. pv := makePersistentVolume(serverIP, bindTo)
  131. By(fmt.Sprintf("Creating a PVC followed by a%s PV", preBindMsg))
  132. // instantiate the pvc
  133. pvc, err := createPVC(c, ns, pvc)
  134. if err != nil {
  135. return nil, nil, err
  136. }
  137. // instantiate the pvc, handle pre-binding by ClaimRef if needed
  138. if preBind {
  139. pv.Spec.ClaimRef.Name = pvc.Name
  140. }
  141. pv, err = createPV(c, pv)
  142. if err != nil {
  143. return nil, pvc, err
  144. }
  145. return pv, pvc, nil
  146. }
  147. // Create a PV followed by the PVC based on the passed in nfs-server ip and
  148. // namespace. If the "preBind" bool is true then pre-bind the PVC to the PV
  149. // via the PVC's VolumeName. Return the pv and pvc to reflect the created
  150. // objects.
  151. // Note: the pv and pvc are returned back to the It() caller so that the
  152. // AfterEach func can delete these objects if they are not nil.
  153. // Note: in the pre-bind case the real PV name, which is generated, is not
  154. // known until after the PV is instantiated. This is why the pv is created
  155. // before the pvc.
  156. func createPVPVC(c *client.Client, serverIP, ns string, preBind bool) (*api.PersistentVolume, *api.PersistentVolumeClaim, error) {
  157. preBindMsg := ""
  158. if preBind {
  159. preBindMsg = " pre-bound"
  160. }
  161. By(fmt.Sprintf("Creating a PV followed by a%s PVC", preBindMsg))
  162. // make the pv and pvc definitions
  163. pv := makePersistentVolume(serverIP, nil)
  164. pvc := makePersistentVolumeClaim(ns)
  165. // instantiate the pv
  166. pv, err := createPV(c, pv)
  167. if err != nil {
  168. return nil, nil, err
  169. }
  170. // instantiate the pvc, handle pre-binding by VolumeName if needed
  171. if preBind {
  172. pvc.Spec.VolumeName = pv.Name
  173. }
  174. pvc, err = createPVC(c, ns, pvc)
  175. if err != nil {
  176. return pv, nil, err
  177. }
  178. return pv, pvc, nil
  179. }
  180. // Wait for the pv and pvc to bind to each other. Fail test on errors.
  181. func waitOnPVandPVC(c *client.Client, ns string, pv *api.PersistentVolume, pvc *api.PersistentVolumeClaim) error {
  182. // Wait for newly created PVC to bind to the PV
  183. framework.Logf("Waiting for PV %v to bind to PVC %v", pv.Name, pvc.Name)
  184. err := framework.WaitForPersistentVolumeClaimPhase(api.ClaimBound, c, ns, pvc.Name, 3*time.Second, 300*time.Second)
  185. if err != nil {
  186. return fmt.Errorf("PersistentVolumeClaim failed to enter a bound state: %+v", err)
  187. }
  188. // Wait for PersistentVolume.Status.Phase to be Bound, which it should be
  189. // since the PVC is already bound.
  190. err = framework.WaitForPersistentVolumePhase(api.VolumeBound, c, pv.Name, 3*time.Second, 300*time.Second)
  191. if err != nil {
  192. return fmt.Errorf("PersistentVolume failed to enter a bound state even though PVC is Bound: %+v", err)
  193. }
  194. return nil
  195. }
  196. // Waits for the pv and pvc to be bound to each other, then checks that the pv's
  197. // claimRef matches the pvc. Fails test on errors. Return the pv and pvc to
  198. // reflect that these resources have been retrieved again (Get).
  199. // Note: the pv and pvc are returned back to the It() caller so that the
  200. // AfterEach func can delete these objects if they are not nil.
  201. func waitAndValidatePVandPVC(c *client.Client, ns string, pv *api.PersistentVolume, pvc *api.PersistentVolumeClaim) (*api.PersistentVolume, *api.PersistentVolumeClaim, error) {
  202. var err error
  203. // Wait for pv and pvc to bind to each other
  204. if err = waitOnPVandPVC(c, ns, pv, pvc); err != nil {
  205. return pv, pvc, err
  206. }
  207. // Check that the PersistentVolume.ClaimRef is valid and matches the PVC
  208. framework.Logf("Checking PersistentVolume ClaimRef is non-nil")
  209. pv, err = c.PersistentVolumes().Get(pv.Name)
  210. if err != nil {
  211. return pv, pvc, fmt.Errorf("Cannot re-get PersistentVolume %v:", pv.Name)
  212. }
  213. pvc, err = c.PersistentVolumeClaims(ns).Get(pvc.Name)
  214. if err != nil {
  215. return pv, pvc, fmt.Errorf("Cannot re-get PersistentVolumeClaim %v:", pvc.Name)
  216. }
  217. if pv.Spec.ClaimRef == nil || pv.Spec.ClaimRef.UID != pvc.UID {
  218. pvJSON, _ := json.Marshal(pv.Spec.ClaimRef)
  219. return pv, pvc, fmt.Errorf("Expected Bound PersistentVolume %v to have valid ClaimRef: %+v", pv.Name, string(pvJSON))
  220. }
  221. return pv, pvc, nil
  222. }
  223. // Test the pod's exitcode to be zero.
  224. func testPodSuccessOrFail(f *framework.Framework, c *client.Client, ns string, pod *api.Pod) error {
  225. By("Pod should terminate with exitcode 0 (success)")
  226. err := framework.WaitForPodSuccessInNamespace(c, pod.Name, pod.Spec.Containers[0].Name, ns)
  227. if err != nil {
  228. return fmt.Errorf("Pod %v returned non-zero exitcode: %+v", pod.Name, err)
  229. }
  230. framework.Logf("pod %v exited successfully", pod.Name)
  231. return nil
  232. }
  233. // Delete the passed in pod.
  234. func deletePod(f *framework.Framework, c *client.Client, ns string, pod *api.Pod) error {
  235. framework.Logf("Deleting pod %v", pod.Name)
  236. err := c.Pods(ns).Delete(pod.Name, nil)
  237. if err != nil {
  238. return fmt.Errorf("Pod %v encountered a delete error: %v", pod.Name, err)
  239. }
  240. // Wait for pod to terminate
  241. err = f.WaitForPodTerminated(pod.Name, "")
  242. if err != nil && !apierrs.IsNotFound(err) {
  243. return fmt.Errorf("Pod %v will not teminate: %v", pod.Name, err)
  244. }
  245. // Re-get the pod to double check that it has been deleted; expect err
  246. // Note: Get() writes a log error if the pod is not found
  247. _, err = c.Pods(ns).Get(pod.Name)
  248. if err == nil {
  249. return fmt.Errorf("Pod %v has been deleted but able to re-Get the deleted pod", pod.Name)
  250. }
  251. if !apierrs.IsNotFound(err) {
  252. return fmt.Errorf("Pod %v has been deleted but still exists: %v", pod.Name, err)
  253. }
  254. framework.Logf("Ignore \"not found\" error above. Pod %v successfully deleted", pod.Name)
  255. return nil
  256. }
  257. // Create the test pod, wait for (hopefully) success, and then delete the pod.
  258. func createWaitAndDeletePod(f *framework.Framework, c *client.Client, ns string, claimName string) error {
  259. var errmsg string
  260. framework.Logf("Creating nfs test pod")
  261. // Make pod spec
  262. pod := makeWritePod(ns, claimName)
  263. // Instantiate pod (Create)
  264. runPod, err := c.Pods(ns).Create(pod)
  265. if err != nil || runPod == nil {
  266. name := ""
  267. if runPod != nil {
  268. name = runPod.Name
  269. }
  270. return fmt.Errorf("Create test pod %v failed: %v", name, err)
  271. }
  272. // Wait for the test pod to complete its lifecycle
  273. podErr := testPodSuccessOrFail(f, c, ns, runPod)
  274. // Regardless of podErr above, delete the pod if it exists
  275. if runPod != nil {
  276. err = deletePod(f, c, ns, runPod)
  277. }
  278. // Check results of pod success and pod delete
  279. if podErr != nil {
  280. errmsg = fmt.Sprintf("Pod %v exited with non-zero exitcode: %v", runPod.Name, podErr)
  281. }
  282. if err != nil { // Delete error
  283. if len(errmsg) > 0 {
  284. errmsg += "; and "
  285. }
  286. errmsg += fmt.Sprintf("Delete error on pod %v: %v", runPod.Name, err)
  287. }
  288. if len(errmsg) > 0 {
  289. return fmt.Errorf(errmsg)
  290. }
  291. return nil
  292. }
  293. // validate PV/PVC, create and verify writer pod, delete PVC and PV. Ensure
  294. // all of these steps were successful. Return the pv and pvc to reflect that
  295. // these resources have been retrieved again (Get).
  296. // Note: the pv and pvc are returned back to the It() caller so that the
  297. // AfterEach func can delete these objects if they are not nil.
  298. func completeTest(f *framework.Framework, c *client.Client, ns string, pv *api.PersistentVolume, pvc *api.PersistentVolumeClaim) (*api.PersistentVolume, *api.PersistentVolumeClaim, error) {
  299. // 1. verify that the PV and PVC have binded correctly
  300. By("Validating the PV-PVC binding")
  301. pv, pvc, err := waitAndValidatePVandPVC(c, ns, pv, pvc)
  302. if err != nil {
  303. return pv, pvc, err
  304. }
  305. // 2. create the nfs writer pod, test if the write was successful,
  306. // then delete the pod and verify that it was deleted
  307. By("Checking pod has write access to PersistentVolume")
  308. if err = createWaitAndDeletePod(f, c, ns, pvc.Name); err != nil {
  309. return pv, pvc, err
  310. }
  311. // 3. delete the PVC before deleting PV, wait for PV to be "Available"
  312. By("Deleting the PVC to invoke the recycler")
  313. pv, pvc, err = deletePVCandValidatePV(c, ns, pvc, pv)
  314. if err != nil {
  315. return pv, pvc, err
  316. }
  317. // 4. cleanup by deleting the pv
  318. By("Deleting the PV")
  319. if pv, err = deletePersistentVolume(c, pv); err != nil {
  320. return pv, pvc, err
  321. }
  322. return pv, pvc, nil
  323. }
  324. var _ = framework.KubeDescribe("PersistentVolumes", func() {
  325. // global vars for the It() tests below
  326. f := framework.NewDefaultFramework("pv")
  327. var c *client.Client
  328. var ns string
  329. var NFSconfig VolumeTestConfig
  330. var serverIP string
  331. var nfsServerPod *api.Pod
  332. var pv *api.PersistentVolume
  333. var pvc *api.PersistentVolumeClaim
  334. var err error
  335. // config for the nfs-server pod in the default namespace
  336. NFSconfig = VolumeTestConfig{
  337. namespace: api.NamespaceDefault,
  338. prefix: "nfs",
  339. serverImage: "gcr.io/google_containers/volume-nfs:0.6",
  340. serverPorts: []int{2049},
  341. serverArgs: []string{"-G", "777", "/exports"},
  342. }
  343. BeforeEach(func() {
  344. c = f.Client
  345. ns = f.Namespace.Name
  346. // If it doesn't exist, create the nfs server pod in "default" ns
  347. // The "default" ns is used so that individual tests can delete
  348. // their ns without impacting the nfs-server pod.
  349. if nfsServerPod == nil {
  350. nfsServerPod = startVolumeServer(c, NFSconfig)
  351. serverIP = nfsServerPod.Status.PodIP
  352. framework.Logf("NFS server IP address: %v", serverIP)
  353. }
  354. })
  355. AfterEach(func() {
  356. if c != nil && len(ns) > 0 { // still have client and namespace
  357. if pvc != nil && len(pvc.Name) > 0 {
  358. // Delete the PersistentVolumeClaim
  359. framework.Logf("AfterEach: PVC %v is non-nil, deleting claim", pvc.Name)
  360. err := c.PersistentVolumeClaims(ns).Delete(pvc.Name)
  361. if err != nil && !apierrs.IsNotFound(err) {
  362. framework.Logf("AfterEach: delete of PersistentVolumeClaim %v error: %v", pvc.Name, err)
  363. }
  364. pvc = nil
  365. }
  366. if pv != nil && len(pv.Name) > 0 {
  367. framework.Logf("AfterEach: PV %v is non-nil, deleting pv", pv.Name)
  368. err := c.PersistentVolumes().Delete(pv.Name)
  369. if err != nil && !apierrs.IsNotFound(err) {
  370. framework.Logf("AfterEach: delete of PersistentVolume %v error: %v", pv.Name, err)
  371. }
  372. pv = nil
  373. }
  374. }
  375. })
  376. // Execute after *all* the tests have run
  377. AddCleanupAction(func() {
  378. if nfsServerPod != nil && c != nil {
  379. framework.Logf("AfterSuite: nfs-server pod %v is non-nil, deleting pod", nfsServerPod.Name)
  380. nfsServerPodCleanup(c, NFSconfig)
  381. nfsServerPod = nil
  382. }
  383. })
  384. // Individual tests follow:
  385. //
  386. // Create an nfs PV, then a claim that matches the PV, and a pod that
  387. // contains the claim. Verify that the PV and PVC bind correctly, and
  388. // that the pod can write to the nfs volume.
  389. It("should create a non-pre-bound PV and PVC: test write access [Flaky]", func() {
  390. pv, pvc, err = createPVPVC(c, serverIP, ns, false)
  391. if err != nil {
  392. framework.Failf("%v", err)
  393. }
  394. // validate PV-PVC, create and verify writer pod, delete PVC
  395. // and PV
  396. pv, pvc, err = completeTest(f, c, ns, pv, pvc)
  397. if err != nil {
  398. framework.Failf("%v", err)
  399. }
  400. })
  401. // Create a claim first, then a nfs PV that matches the claim, and a
  402. // pod that contains the claim. Verify that the PV and PVC bind
  403. // correctly, and that the pod can write to the nfs volume.
  404. It("create a PVC and non-pre-bound PV: test write access [Flaky]", func() {
  405. pv, pvc, err = createPVCPV(c, serverIP, ns, false)
  406. if err != nil {
  407. framework.Failf("%v", err)
  408. }
  409. // validate PV-PVC, create and verify writer pod, delete PVC
  410. // and PV
  411. pv, pvc, err = completeTest(f, c, ns, pv, pvc)
  412. if err != nil {
  413. framework.Failf("%v", err)
  414. }
  415. })
  416. // Create a claim first, then a pre-bound nfs PV that matches the claim,
  417. // and a pod that contains the claim. Verify that the PV and PVC bind
  418. // correctly, and that the pod can write to the nfs volume.
  419. It("create a PVC and a pre-bound PV: test write access [Flaky]", func() {
  420. pv, pvc, err = createPVCPV(c, serverIP, ns, true)
  421. if err != nil {
  422. framework.Failf("%v", err)
  423. }
  424. // validate PV-PVC, create and verify writer pod, delete PVC
  425. // and PV
  426. pv, pvc, err = completeTest(f, c, ns, pv, pvc)
  427. if err != nil {
  428. framework.Failf("%v", err)
  429. }
  430. })
  431. // Create a nfs PV first, then a pre-bound PVC that matches the PV,
  432. // and a pod that contains the claim. Verify that the PV and PVC bind
  433. // correctly, and that the pod can write to the nfs volume.
  434. It("create a PV and a pre-bound PVC: test write access [Flaky]", func() {
  435. pv, pvc, err = createPVPVC(c, serverIP, ns, true)
  436. if err != nil {
  437. framework.Failf("%v", err)
  438. }
  439. // validate PV-PVC, create and verify writer pod, delete PVC
  440. // and PV
  441. pv, pvc, err = completeTest(f, c, ns, pv, pvc)
  442. if err != nil {
  443. framework.Failf("%v", err)
  444. }
  445. })
  446. })
  447. // Returns a PV definition based on the nfs server IP. If the PVC is not nil
  448. // then the PV is defined with a ClaimRef which includes the PVC's namespace.
  449. // If the PVC is nil then the PV is not defined with a ClaimRef.
  450. // Note: the passed-in claim does not have a name until it is created
  451. // (instantiated) and thus the PV's ClaimRef cannot be completely filled-in in
  452. // this func. Therefore, the ClaimRef's name is added later in
  453. // createPVCPV.
  454. func makePersistentVolume(serverIP string, pvc *api.PersistentVolumeClaim) *api.PersistentVolume {
  455. // Specs are expected to match this test's PersistentVolumeClaim
  456. var claimRef *api.ObjectReference
  457. if pvc != nil {
  458. claimRef = &api.ObjectReference{
  459. Name: pvc.Name,
  460. Namespace: pvc.Namespace,
  461. }
  462. }
  463. return &api.PersistentVolume{
  464. ObjectMeta: api.ObjectMeta{
  465. GenerateName: "nfs-",
  466. Annotations: map[string]string{
  467. volumehelper.VolumeGidAnnotationKey: "777",
  468. },
  469. },
  470. Spec: api.PersistentVolumeSpec{
  471. PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimRecycle,
  472. Capacity: api.ResourceList{
  473. api.ResourceName(api.ResourceStorage): resource.MustParse("2Gi"),
  474. },
  475. PersistentVolumeSource: api.PersistentVolumeSource{
  476. NFS: &api.NFSVolumeSource{
  477. Server: serverIP,
  478. Path: "/exports",
  479. ReadOnly: false,
  480. },
  481. },
  482. AccessModes: []api.PersistentVolumeAccessMode{
  483. api.ReadWriteOnce,
  484. api.ReadOnlyMany,
  485. api.ReadWriteMany,
  486. },
  487. ClaimRef: claimRef,
  488. },
  489. }
  490. }
  491. // Returns a PVC definition based on the namespace.
  492. // Note: if this PVC is intended to be pre-bound to a PV, whose name is not
  493. // known until the PV is instantiated, then the func createPVPVC will add
  494. // pvc.Spec.VolumeName to this claim.
  495. func makePersistentVolumeClaim(ns string) *api.PersistentVolumeClaim {
  496. // Specs are expected to match this test's PersistentVolume
  497. return &api.PersistentVolumeClaim{
  498. ObjectMeta: api.ObjectMeta{
  499. GenerateName: "pvc-",
  500. Namespace: ns,
  501. },
  502. Spec: api.PersistentVolumeClaimSpec{
  503. AccessModes: []api.PersistentVolumeAccessMode{
  504. api.ReadWriteOnce,
  505. api.ReadOnlyMany,
  506. api.ReadWriteMany,
  507. },
  508. Resources: api.ResourceRequirements{
  509. Requests: api.ResourceList{
  510. api.ResourceName(api.ResourceStorage): resource.MustParse("1Gi"),
  511. },
  512. },
  513. },
  514. }
  515. }
  516. // Returns a pod definition based on the namespace. The pod references the PVC's
  517. // name.
  518. func makeWritePod(ns string, pvcName string) *api.Pod {
  519. // Prepare pod that mounts the NFS volume again and
  520. // checks that /mnt/index.html was scrubbed there
  521. var isPrivileged bool = true
  522. return &api.Pod{
  523. TypeMeta: unversioned.TypeMeta{
  524. Kind: "Pod",
  525. APIVersion: testapi.Default.GroupVersion().String(),
  526. },
  527. ObjectMeta: api.ObjectMeta{
  528. GenerateName: "write-pod-",
  529. Namespace: ns,
  530. },
  531. Spec: api.PodSpec{
  532. Containers: []api.Container{
  533. {
  534. Name: "write-pod",
  535. Image: "gcr.io/google_containers/busybox:1.24",
  536. Command: []string{"/bin/sh"},
  537. Args: []string{"-c", "touch /mnt/SUCCESS && (id -G | grep -E '\\b777\\b')"},
  538. VolumeMounts: []api.VolumeMount{
  539. {
  540. Name: "nfs-pvc",
  541. MountPath: "/mnt",
  542. },
  543. },
  544. SecurityContext: &api.SecurityContext{
  545. Privileged: &isPrivileged,
  546. },
  547. },
  548. },
  549. Volumes: []api.Volume{
  550. {
  551. Name: "nfs-pvc",
  552. VolumeSource: api.VolumeSource{
  553. PersistentVolumeClaim: &api.PersistentVolumeClaimVolumeSource{
  554. ClaimName: pvcName,
  555. },
  556. },
  557. },
  558. },
  559. },
  560. }
  561. }