-
Notifications
You must be signed in to change notification settings - Fork 173
/
csi_static_provisioning_basic.go
217 lines (182 loc) · 8.1 KB
/
csi_static_provisioning_basic.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package e2e
import (
"context"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/object"
"github.com/onsi/ginkgo"
"github.com/onsi/gomega"
v1 "k8s.io/api/core/v1"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/kubernetes/test/e2e/framework"
)
var _ = ginkgo.Describe("[csi-block-e2e] Basic Static Provisioning", func() {
f := framework.NewDefaultFramework("e2e-csistaticprovision")
var (
client clientset.Interface
namespace string
fcdID string
pv *v1.PersistentVolume
pvc *v1.PersistentVolumeClaim
defaultDatacenter *object.Datacenter
defaultDatastore *object.Datastore
deleteFCDRequired bool
pandoraSyncWaitTime int
err error
datastoreURL string
)
ginkgo.BeforeEach(func() {
bootstrap()
client = f.ClientSet
namespace = f.Namespace.Name
nodeList := framework.GetReadySchedulableNodesOrDie(f.ClientSet)
if !(len(nodeList.Items) > 0) {
framework.Failf("Unable to find ready and schedulable Node")
}
if os.Getenv(envPandoraSyncWaitTime) != "" {
pandoraSyncWaitTime, err = strconv.Atoi(os.Getenv(envPandoraSyncWaitTime))
gomega.Expect(err).NotTo(gomega.HaveOccurred())
} else {
pandoraSyncWaitTime = defaultPandoraSyncWaitTime
}
deleteFCDRequired = false
var datacenters []string
datastoreURL = GetAndExpectStringEnvVar(envSharedDatastoreURL)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
finder := find.NewFinder(e2eVSphere.Client.Client, false)
cfg, err := getConfig()
gomega.Expect(err).NotTo(gomega.HaveOccurred())
dcList := strings.Split(cfg.Global.Datacenters, ",")
for _, dc := range dcList {
dcName := strings.TrimSpace(dc)
if dcName != "" {
datacenters = append(datacenters, dcName)
}
}
for _, dc := range datacenters {
defaultDatacenter, err = finder.Datacenter(ctx, dc)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
finder.SetDatacenter(defaultDatacenter)
defaultDatastore, err = getDatastoreByURL(ctx, datastoreURL, defaultDatacenter)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
}
})
ginkgo.AfterEach(func() {
ginkgo.By("Performing test cleanup")
if deleteFCDRequired {
ginkgo.By(fmt.Sprintf("Deleting FCD: %s", fcdID))
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
err := e2eVSphere.deleteFCD(ctx, fcdID, defaultDatastore.Reference())
gomega.Expect(err).NotTo(gomega.HaveOccurred())
}
if pvc != nil {
framework.ExpectNoError(framework.DeletePersistentVolumeClaim(client, pvc.Name, namespace), "Failed to delete PVC ", pvc.Name)
}
if pv != nil {
framework.ExpectNoError(framework.WaitForPersistentVolumeDeleted(client, pv.Name, poll, pollTimeoutShort))
framework.ExpectNoError(e2eVSphere.waitForCNSVolumeToBeDeleted(pv.Spec.CSI.VolumeHandle))
}
})
/*
This test verifies the static provisioning workflow.
Test Steps:
1. Create FCD and wait for fcd to allow syncing with pandora.
2. Create PV Spec with volumeID set to FCDID created in Step-1, and PersistentVolumeReclaimPolicy is set to Delete.
3. Create PVC with the storage request set to PV's storage capacity.
4. Wait for PV and PVC to bound.
5. Create a POD.
6. Verify volume is attached to the node and volume is accessible in the pod.
7. Verify container volume metadata is present in CNS cache.
8. Delete POD.
9. Verify volume is detached from the node.
10. Delete PVC.
11. Verify PV is deleted automatically.
*/
ginkgo.It("Verify basic static provisioning workflow", func() {
var err error
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ginkgo.By("Creating FCD Disk")
fcdID, err := e2eVSphere.createFCD(ctx, "BasicStaticFCD", diskSizeInMb, defaultDatastore.Reference())
gomega.Expect(err).NotTo(gomega.HaveOccurred())
deleteFCDRequired = true
ginkgo.By(fmt.Sprintf("Sleeping for %v seconds to allow newly created FCD:%s to sync with pandora", pandoraSyncWaitTime, fcdID))
time.Sleep(time.Duration(pandoraSyncWaitTime) * time.Second)
// Creating label for PV.
// PVC will use this label as Selector to find PV
staticPVLabels := make(map[string]string)
staticPVLabels["fcd-id"] = fcdID
ginkgo.By("Creating the PV")
pv = getPersistentVolumeSpec(fcdID, v1.PersistentVolumeReclaimDelete, staticPVLabels)
pv, err = client.CoreV1().PersistentVolumes().Create(pv)
if err != nil {
return
}
err = e2eVSphere.waitForCNSVolumeToBeCreated(pv.Spec.CSI.VolumeHandle)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
ginkgo.By("Creating the PVC")
pvc = getPersistentVolumeClaimSpec(namespace, staticPVLabels, pv.Name)
pvc, err = client.CoreV1().PersistentVolumeClaims(namespace).Create(pvc)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
// Wait for PV and PVC to Bind
framework.ExpectNoError(framework.WaitOnPVandPVC(client, namespace, pv, pvc))
// Set deleteFCDRequired to false.
// After PV, PVC is in the bind state, Deleting PVC should delete container volume.
// So no need to delete FCD directly using vSphere API call.
deleteFCDRequired = false
ginkgo.By("Verifying CNS entry is present in cache")
_, err = e2eVSphere.queryCNSVolumeWithResult(pv.Spec.CSI.VolumeHandle)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
ginkgo.By("Creating the Pod")
var pvclaims []*v1.PersistentVolumeClaim
pvclaims = append(pvclaims, pvc)
pod, err := framework.CreatePod(client, namespace, nil, pvclaims, false, "")
gomega.Expect(err).NotTo(gomega.HaveOccurred())
ginkgo.By(fmt.Sprintf("Verify the volume attached to the node: %s", pod.Spec.NodeName))
isDiskAttached, err := e2eVSphere.isVolumeAttachedToNode(client, pv.Spec.CSI.VolumeHandle, pod.Spec.NodeName)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
gomega.Expect(isDiskAttached).To(gomega.BeTrue(), fmt.Sprintf("Volume is not attached"))
ginkgo.By("Verify the volume is accessible and available to the pod by creating an empty file")
filepath := filepath.Join("/mnt/volume1", "/emptyFile.txt")
_, err = framework.LookForStringInPodExec(namespace, pod.Name, []string{"/bin/touch", filepath}, "", time.Minute)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
ginkgo.By("Verify container volume metadata is present in CNS cache")
ginkgo.By(fmt.Sprintf("Invoking QueryCNSVolume with VolumeID: %s", pv.Spec.CSI.VolumeHandle))
_, err = e2eVSphere.queryCNSVolumeWithResult(pv.Spec.CSI.VolumeHandle)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
ginkgo.By("Verify container volume metadata is matching the one in CNS cache")
err = verifyVolumeMetadataInCNS(&e2eVSphere, pv.Spec.CSI.VolumeHandle, pvc.Name, pv.ObjectMeta.Name, pod.Name)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
ginkgo.By("Deleting the Pod")
framework.ExpectNoError(framework.DeletePodWithWait(f, client, pod), "Failed to delete pod ", pod.Name)
ginkgo.By(fmt.Sprintf("Verify volume is detached from the node: %s", pod.Spec.NodeName))
isDiskDetached, err := e2eVSphere.waitForVolumeDetachedFromNode(client, pv.Spec.CSI.VolumeHandle, pod.Spec.NodeName)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
gomega.Expect(isDiskDetached).To(gomega.BeTrue(), fmt.Sprintf("Volume is not detached from the node"))
ginkgo.By("Deleting the PV Claim")
framework.ExpectNoError(framework.DeletePersistentVolumeClaim(client, pvc.Name, namespace), "Failed to delete PVC ", pvc.Name)
pvc = nil
ginkgo.By("Verify PV should be deleted automatically")
framework.ExpectNoError(framework.WaitForPersistentVolumeDeleted(client, pv.Name, poll, pollTimeoutShort))
pv = nil
})
})