Skip to content

Commit 5e1dc30

Browse files
committed
test: restart driver e2e test
fix
1 parent e63fd9e commit 5e1dc30

File tree

4 files changed

+217
-2
lines changed

4 files changed

+217
-2
lines changed

test/e2e/dynamic_provisioning_test.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,4 +568,92 @@ var _ = ginkgo.Describe("[blob-csi-e2e] Dynamic Provisioning", func() {
568568
}
569569
test.Run(cs, ns)
570570
})
571+
572+
ginkgo.It("nfs volume mount is still valid after driver restart [blob.csi.azure.com]", func() {
573+
// print driver logs before driver restart
574+
blobLog := testCmd{
575+
command: "bash",
576+
args: []string{"test/utils/blob_log.sh"},
577+
startLog: "===================blob log (before restart)===================",
578+
endLog: "====================================================================",
579+
}
580+
execTestCmd([]testCmd{blobLog})
581+
582+
pod := testsuites.PodDetails{
583+
Cmd: "echo 'hello world' >> /mnt/test-1/data && while true; do sleep 3600; done",
584+
Volumes: []testsuites.VolumeDetails{
585+
{
586+
ClaimSize: "10Gi",
587+
VolumeMount: testsuites.VolumeMountDetails{
588+
NameGenerate: "test-volume-",
589+
MountPathGenerate: "/mnt/test-",
590+
},
591+
},
592+
},
593+
}
594+
595+
podCheckCmd := []string{"cat", "/mnt/test-1/data"}
596+
expectedString := "hello world\n"
597+
test := testsuites.DynamicallyProvisionedRestartDriverTest{
598+
CSIDriver: testDriver,
599+
Pod: pod,
600+
PodCheck: &testsuites.PodExecCheck{
601+
Cmd: podCheckCmd,
602+
ExpectedString: expectedString,
603+
},
604+
StorageClassParameters: map[string]string{"protocol": "nfs"},
605+
RestartDriverFunc: func() {
606+
restartDriver := testCmd{
607+
command: "bash",
608+
args: []string{"test/utils/restart_driver_daemonset.sh"},
609+
startLog: "Restart driver node daemonset ...",
610+
endLog: "Restart driver node daemonset done successfully",
611+
}
612+
execTestCmd([]testCmd{restartDriver})
613+
},
614+
}
615+
test.Run(cs, ns)
616+
})
617+
618+
ginkgo.It("blobfuse volume mount is still valid after driver restart [blob.csi.azure.com]", func() {
619+
_, useBlobfuseProxy := os.LookupEnv("ENABLE_BLOBFUSE_PROXY")
620+
if !useBlobfuseProxy {
621+
ginkgo.Skip("skip this test since blobfuse-proxy is not enabled")
622+
}
623+
624+
pod := testsuites.PodDetails{
625+
Cmd: "echo 'hello world' >> /mnt/test-1/data && while true; do sleep 3600; done",
626+
Volumes: []testsuites.VolumeDetails{
627+
{
628+
ClaimSize: "10Gi",
629+
VolumeMount: testsuites.VolumeMountDetails{
630+
NameGenerate: "test-volume-",
631+
MountPathGenerate: "/mnt/test-",
632+
},
633+
},
634+
},
635+
}
636+
637+
podCheckCmd := []string{"cat", "/mnt/test-1/data"}
638+
expectedString := "hello world\n"
639+
test := testsuites.DynamicallyProvisionedRestartDriverTest{
640+
CSIDriver: testDriver,
641+
Pod: pod,
642+
PodCheck: &testsuites.PodExecCheck{
643+
Cmd: podCheckCmd,
644+
ExpectedString: expectedString,
645+
},
646+
StorageClassParameters: map[string]string{"skuName": "Standard_LRS"},
647+
RestartDriverFunc: func() {
648+
restartDriver := testCmd{
649+
command: "bash",
650+
args: []string{"test/utils/restart_driver_daemonset.sh"},
651+
startLog: "Restart driver node daemonset ...",
652+
endLog: "Restart driver node daemonset done successfully",
653+
}
654+
execTestCmd([]testCmd{restartDriver})
655+
},
656+
}
657+
test.Run(cs, ns)
658+
})
571659
})
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
Copyright 2021 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package testsuites
18+
19+
import (
20+
"github.com/onsi/ginkgo"
21+
v1 "k8s.io/api/core/v1"
22+
clientset "k8s.io/client-go/kubernetes"
23+
24+
"sigs.k8s.io/blob-csi-driver/test/e2e/driver"
25+
)
26+
27+
// DynamicallyProvisionedRestartDriverTest will test to ensure that restarting driver doesn't affect pod mounting.
28+
// It will mount a pod, restart the driver daemonset and ensure that the pod still has access to original volume.
29+
type DynamicallyProvisionedRestartDriverTest struct {
30+
CSIDriver driver.DynamicPVTestDriver
31+
Pod PodDetails
32+
PodCheck *PodExecCheck
33+
StorageClassParameters map[string]string
34+
RestartDriverFunc func()
35+
}
36+
37+
func (t *DynamicallyProvisionedRestartDriverTest) Run(client clientset.Interface, namespace *v1.Namespace) {
38+
tDeployment, cleanup := t.Pod.SetupDeployment(client, namespace, t.CSIDriver, t.StorageClassParameters)
39+
// defer must be called here for resources not get removed before using them
40+
for i := range cleanup {
41+
defer cleanup[i]()
42+
}
43+
44+
ginkgo.By("creating the deployment for the pod")
45+
tDeployment.Create()
46+
47+
ginkgo.By("checking that the pod is running")
48+
tDeployment.WaitForPodReady()
49+
50+
if t.PodCheck != nil {
51+
ginkgo.By("checking if pod is able to access volume")
52+
tDeployment.PollForStringInPodsExec(t.PodCheck.Cmd, t.PodCheck.ExpectedString)
53+
}
54+
55+
// restart the driver
56+
ginkgo.By("restarting the driver daemonset")
57+
t.RestartDriverFunc()
58+
59+
// check if original pod could still access volume
60+
if t.PodCheck != nil {
61+
ginkgo.By("checking if pod still has access to volume after driver restart")
62+
tDeployment.PollForStringInPodsExec(t.PodCheck.Cmd, t.PodCheck.ExpectedString)
63+
}
64+
}

test/e2e/testsuites/testsuites.go

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"context"
2121
"fmt"
2222
"math/rand"
23+
"strings"
2324
"time"
2425

2526
"sigs.k8s.io/blob-csi-driver/pkg/blob"
@@ -35,6 +36,8 @@ import (
3536
"k8s.io/apimachinery/pkg/api/resource"
3637
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3738
"k8s.io/apimachinery/pkg/fields"
39+
"k8s.io/apimachinery/pkg/util/errors"
40+
"k8s.io/apimachinery/pkg/util/wait"
3841
clientset "k8s.io/client-go/kubernetes"
3942
"k8s.io/kubernetes/pkg/kubelet/events"
4043
"k8s.io/kubernetes/test/e2e/framework"
@@ -54,8 +57,9 @@ const (
5457
// Description that will printed during tests
5558
failedConditionDescription = "Error status code"
5659

57-
poll = 2 * time.Second
58-
pollLongTimeout = 5 * time.Minute
60+
poll = 2 * time.Second
61+
pollLongTimeout = 5 * time.Minute
62+
pollForStringTimeout = 1 * time.Minute
5963
)
6064

6165
type TestStorageClass struct {
@@ -379,6 +383,10 @@ func (t *TestDeployment) Exec(command []string, expectedString string) {
379383
framework.ExpectNoError(err)
380384
}
381385

386+
func (t *TestDeployment) PollForStringInPodsExec(command []string, expectedString string) {
387+
pollForStringInPodsExec(t.namespace.Name, []string{t.podName}, command, expectedString)
388+
}
389+
382390
func (t *TestDeployment) DeletePodAndWait() {
383391
e2elog.Logf("Deleting pod %q in namespace %q", t.podName, t.namespace.Name)
384392
err := t.client.CoreV1().Pods(t.namespace.Name).Delete(context.TODO(), t.podName, metav1.DeleteOptions{})
@@ -629,3 +637,33 @@ func waitForPersistentVolumeClaimDeleted(c clientset.Interface, ns string, pvcNa
629637
}
630638
return fmt.Errorf("PersistentVolumeClaim %s is not removed from the system within %v", pvcName, timeout)
631639
}
640+
641+
func pollForStringWorker(namespace string, pod string, command []string, expectedString string, ch chan<- error) {
642+
args := append([]string{"exec", pod, "--"}, command...)
643+
err := wait.PollImmediate(poll, pollForStringTimeout, func() (bool, error) {
644+
stdout, err := framework.RunKubectl(namespace, args...)
645+
if err != nil {
646+
framework.Logf("Error waiting for output %q in pod %q: %v.", expectedString, pod, err)
647+
return false, nil
648+
}
649+
if !strings.Contains(stdout, expectedString) {
650+
framework.Logf("The stdout did not contain output %q in pod %q, found: %q.", expectedString, pod, stdout)
651+
return false, nil
652+
}
653+
return true, nil
654+
})
655+
ch <- err
656+
}
657+
658+
// Execute the command for all pods in the namespace, looking for expectedString in stdout
659+
func pollForStringInPodsExec(namespace string, pods []string, command []string, expectedString string) {
660+
ch := make(chan error, len(pods))
661+
for _, pod := range pods {
662+
go pollForStringWorker(namespace, pod, command, expectedString, ch)
663+
}
664+
errs := make([]error, 0, len(pods))
665+
for range pods {
666+
errs = append(errs, <-ch)
667+
}
668+
framework.ExpectNoError(errors.NewAggregate(errs), "Failed to find %q in at least one pod's output.", expectedString)
669+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/bin/bash
2+
3+
# Copyright 2021 The Kubernetes Authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
set -euo pipefail
18+
19+
echo "Deleting the Driver node daemonset ..."
20+
kubectl delete -f ./deploy/csi-blob-node.yaml --ignore-not-found
21+
22+
sleep 15
23+
24+
echo "Installing the Driver node daemonset ..."
25+
kubectl apply -f ./deploy/csi-blob-node.yaml

0 commit comments

Comments
 (0)