vsphere_volume_diskformat.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. Copyright 2017 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package vsphere
  14. import (
  15. "context"
  16. "path/filepath"
  17. "github.com/onsi/ginkgo"
  18. "github.com/onsi/gomega"
  19. "github.com/vmware/govmomi/object"
  20. "github.com/vmware/govmomi/vim25/types"
  21. v1 "k8s.io/api/core/v1"
  22. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  23. "k8s.io/apimachinery/pkg/util/uuid"
  24. clientset "k8s.io/client-go/kubernetes"
  25. "k8s.io/kubernetes/test/e2e/framework"
  26. e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
  27. e2epv "k8s.io/kubernetes/test/e2e/framework/pv"
  28. e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
  29. "k8s.io/kubernetes/test/e2e/storage/utils"
  30. )
  31. /*
  32. Test to verify diskformat specified in storage-class is being honored while volume creation.
  33. Valid and supported options are eagerzeroedthick, zeroedthick and thin
  34. Steps
  35. 1. Create StorageClass with diskformat set to valid type
  36. 2. Create PVC which uses the StorageClass created in step 1.
  37. 3. Wait for PV to be provisioned.
  38. 4. Wait for PVC's status to become Bound
  39. 5. Create pod using PVC on specific node.
  40. 6. Wait for Disk to be attached to the node.
  41. 7. Get node VM's devices and find PV's Volume Disk.
  42. 8. Get Backing Info of the Volume Disk and obtain EagerlyScrub and ThinProvisioned
  43. 9. Based on the value of EagerlyScrub and ThinProvisioned, verify diskformat is correct.
  44. 10. Delete pod and Wait for Volume Disk to be detached from the Node.
  45. 11. Delete PVC, PV and Storage Class
  46. */
  47. var _ = utils.SIGDescribe("Volume Disk Format [Feature:vsphere]", func() {
  48. f := framework.NewDefaultFramework("volume-disk-format")
  49. const (
  50. NodeLabelKey = "vsphere_e2e_label_volume_diskformat"
  51. )
  52. var (
  53. client clientset.Interface
  54. namespace string
  55. nodeName string
  56. isNodeLabeled bool
  57. nodeKeyValueLabel map[string]string
  58. nodeLabelValue string
  59. )
  60. ginkgo.BeforeEach(func() {
  61. e2eskipper.SkipUnlessProviderIs("vsphere")
  62. Bootstrap(f)
  63. client = f.ClientSet
  64. namespace = f.Namespace.Name
  65. if !isNodeLabeled {
  66. nodeName = GetReadySchedulableRandomNodeInfo().Name
  67. nodeLabelValue = "vsphere_e2e_" + string(uuid.NewUUID())
  68. nodeKeyValueLabel = make(map[string]string)
  69. nodeKeyValueLabel[NodeLabelKey] = nodeLabelValue
  70. framework.AddOrUpdateLabelOnNode(client, nodeName, NodeLabelKey, nodeLabelValue)
  71. isNodeLabeled = true
  72. }
  73. })
  74. framework.AddCleanupAction(func() {
  75. // Cleanup actions will be called even when the tests are skipped and leaves namespace unset.
  76. if len(namespace) > 0 && len(nodeLabelValue) > 0 {
  77. framework.RemoveLabelOffNode(client, nodeName, NodeLabelKey)
  78. }
  79. })
  80. ginkgo.It("verify disk format type - eagerzeroedthick is honored for dynamically provisioned pv using storageclass", func() {
  81. ginkgo.By("Invoking Test for diskformat: eagerzeroedthick")
  82. invokeTest(f, client, namespace, nodeName, nodeKeyValueLabel, "eagerzeroedthick")
  83. })
  84. ginkgo.It("verify disk format type - zeroedthick is honored for dynamically provisioned pv using storageclass", func() {
  85. ginkgo.By("Invoking Test for diskformat: zeroedthick")
  86. invokeTest(f, client, namespace, nodeName, nodeKeyValueLabel, "zeroedthick")
  87. })
  88. ginkgo.It("verify disk format type - thin is honored for dynamically provisioned pv using storageclass", func() {
  89. ginkgo.By("Invoking Test for diskformat: thin")
  90. invokeTest(f, client, namespace, nodeName, nodeKeyValueLabel, "thin")
  91. })
  92. })
  93. func invokeTest(f *framework.Framework, client clientset.Interface, namespace string, nodeName string, nodeKeyValueLabel map[string]string, diskFormat string) {
  94. framework.Logf("Invoking Test for DiskFomat: %s", diskFormat)
  95. scParameters := make(map[string]string)
  96. scParameters["diskformat"] = diskFormat
  97. ginkgo.By("Creating Storage Class With DiskFormat")
  98. storageClassSpec := getVSphereStorageClassSpec("thinsc", scParameters, nil, "")
  99. storageclass, err := client.StorageV1().StorageClasses().Create(context.TODO(), storageClassSpec, metav1.CreateOptions{})
  100. framework.ExpectNoError(err)
  101. defer client.StorageV1().StorageClasses().Delete(context.TODO(), storageclass.Name, nil)
  102. ginkgo.By("Creating PVC using the Storage Class")
  103. pvclaimSpec := getVSphereClaimSpecWithStorageClass(namespace, "2Gi", storageclass)
  104. pvclaim, err := client.CoreV1().PersistentVolumeClaims(namespace).Create(context.TODO(), pvclaimSpec, metav1.CreateOptions{})
  105. framework.ExpectNoError(err)
  106. defer func() {
  107. client.CoreV1().PersistentVolumeClaims(namespace).Delete(context.TODO(), pvclaimSpec.Name, nil)
  108. }()
  109. ginkgo.By("Waiting for claim to be in bound phase")
  110. err = e2epv.WaitForPersistentVolumeClaimPhase(v1.ClaimBound, client, pvclaim.Namespace, pvclaim.Name, framework.Poll, framework.ClaimProvisionTimeout)
  111. framework.ExpectNoError(err)
  112. // Get new copy of the claim
  113. pvclaim, err = client.CoreV1().PersistentVolumeClaims(pvclaim.Namespace).Get(context.TODO(), pvclaim.Name, metav1.GetOptions{})
  114. framework.ExpectNoError(err)
  115. // Get the bound PV
  116. pv, err := client.CoreV1().PersistentVolumes().Get(context.TODO(), pvclaim.Spec.VolumeName, metav1.GetOptions{})
  117. framework.ExpectNoError(err)
  118. /*
  119. PV is required to be attached to the Node. so that using govmomi API we can grab Disk's Backing Info
  120. to check EagerlyScrub and ThinProvisioned property
  121. */
  122. ginkgo.By("Creating pod to attach PV to the node")
  123. // Create pod to attach Volume to Node
  124. podSpec := getVSpherePodSpecWithClaim(pvclaim.Name, nodeKeyValueLabel, "while true ; do sleep 2 ; done")
  125. pod, err := client.CoreV1().Pods(namespace).Create(context.TODO(), podSpec, metav1.CreateOptions{})
  126. framework.ExpectNoError(err)
  127. ginkgo.By("Waiting for pod to be running")
  128. gomega.Expect(e2epod.WaitForPodNameRunningInNamespace(client, pod.Name, namespace)).To(gomega.Succeed())
  129. isAttached, err := diskIsAttached(pv.Spec.VsphereVolume.VolumePath, nodeName)
  130. framework.ExpectEqual(isAttached, true)
  131. framework.ExpectNoError(err)
  132. ginkgo.By("Verify Disk Format")
  133. framework.ExpectEqual(verifyDiskFormat(client, nodeName, pv.Spec.VsphereVolume.VolumePath, diskFormat), true, "DiskFormat Verification Failed")
  134. var volumePaths []string
  135. volumePaths = append(volumePaths, pv.Spec.VsphereVolume.VolumePath)
  136. ginkgo.By("Delete pod and wait for volume to be detached from node")
  137. deletePodAndWaitForVolumeToDetach(f, client, pod, nodeName, volumePaths)
  138. }
  139. func verifyDiskFormat(client clientset.Interface, nodeName string, pvVolumePath string, diskFormat string) bool {
  140. ginkgo.By("Verifing disk format")
  141. eagerlyScrub := false
  142. thinProvisioned := false
  143. diskFound := false
  144. pvvmdkfileName := filepath.Base(pvVolumePath) + filepath.Ext(pvVolumePath)
  145. ctx, cancel := context.WithCancel(context.Background())
  146. defer cancel()
  147. nodeInfo := TestContext.NodeMapper.GetNodeInfo(nodeName)
  148. vm := object.NewVirtualMachine(nodeInfo.VSphere.Client.Client, nodeInfo.VirtualMachineRef)
  149. vmDevices, err := vm.Device(ctx)
  150. framework.ExpectNoError(err)
  151. disks := vmDevices.SelectByType((*types.VirtualDisk)(nil))
  152. for _, disk := range disks {
  153. backing := disk.GetVirtualDevice().Backing.(*types.VirtualDiskFlatVer2BackingInfo)
  154. backingFileName := filepath.Base(backing.FileName) + filepath.Ext(backing.FileName)
  155. if backingFileName == pvvmdkfileName {
  156. diskFound = true
  157. if backing.EagerlyScrub != nil {
  158. eagerlyScrub = *backing.EagerlyScrub
  159. }
  160. if backing.ThinProvisioned != nil {
  161. thinProvisioned = *backing.ThinProvisioned
  162. }
  163. break
  164. }
  165. }
  166. framework.ExpectEqual(diskFound, true, "Failed to find disk")
  167. isDiskFormatCorrect := false
  168. if diskFormat == "eagerzeroedthick" {
  169. if eagerlyScrub == true && thinProvisioned == false {
  170. isDiskFormatCorrect = true
  171. }
  172. } else if diskFormat == "zeroedthick" {
  173. if eagerlyScrub == false && thinProvisioned == false {
  174. isDiskFormatCorrect = true
  175. }
  176. } else if diskFormat == "thin" {
  177. if eagerlyScrub == false && thinProvisioned == true {
  178. isDiskFormatCorrect = true
  179. }
  180. }
  181. return isDiskFormatCorrect
  182. }