Skip to content

Commit 826d7a4

Browse files
committed
Enable all the e2e in Windows, retry for SSH
1 parent 1dd02ed commit 826d7a4

File tree

7 files changed

+91
-37
lines changed

7 files changed

+91
-37
lines changed

hack/e2e.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,9 @@ if [ "$PROVIDER" == "gke" ]; then
323323
fi
324324

325325
# legacy path
326-
# --up
327-
# --down
328326
go run $ROOT/hack/e2e.go -- "${kubetest_args[@]}" \
329327
--deployment="$DEPLOYMENT" \
328+
--up \
329+
--down \
330330
--test-cmd="$ROOT/hack/run-e2e.sh" \
331331
"${@:-}"

hack/release.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ ALLOW_OVERRIDE=${ALLOW_OVERRIDE:-}
9191
SKIP_BUILD=${SKIP_BUILD:-}
9292
SKIP_PUSH_LATEST=${SKIP_PUSH_LATEST:-}
9393
LINUX_ARCH=${LINUX_ARCH:-amd64 arm arm64 ppc64le s390x}
94-
WINDOWS_DISTROS=${WINDOWS_DISTROS:-ltsc2019 1909 2004 20H2}
94+
WINDOWS_DISTROS=${WINDOWS_DISTROS:-ltsc2019 1909 2004 20H2 ltsc2022}
9595

9696
echo "REGISTRY: $REGISTRY"
9797
echo "VERSION: $VERSION"

pkg/common/common.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -329,8 +329,8 @@ func ConfigMapDataToVolumeConfig(data map[string]string, provisionerConfig *Prov
329329
if config.MountDir == "" || config.HostDir == "" {
330330
return fmt.Errorf("Storage Class %v is misconfigured, missing HostDir or MountDir parameter", class)
331331
}
332-
config.MountDir = normalizePath(config.MountDir)
333-
config.HostDir = normalizePath(config.HostDir)
332+
config.MountDir = NormalizePath(config.MountDir)
333+
config.HostDir = NormalizePath(config.HostDir)
334334

335335
if config.VolumeMode == "" {
336336
config.VolumeMode = DefaultVolumeMode
@@ -357,10 +357,10 @@ func ConfigMapDataToVolumeConfig(data map[string]string, provisionerConfig *Prov
357357
return nil
358358
}
359359

360-
// normalizePath makes sure the given path is a valid path on Windows too
360+
// NormalizePath makes sure the given path is a valid path on Windows too
361361
// by making sure all instances of `/` are replaced with `\\`, and the
362362
// path beings with `c:`
363-
func normalizePath(path string) string {
363+
func NormalizePath(path string) string {
364364
if runtime.GOOS != "windows" {
365365
return path
366366
}

pkg/discovery/discovery.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,6 @@ func (d *Discoverer) discoverVolumesAtPath(class string, config common.MountConf
267267

268268
// Retrieve list of mount points to iterate through discovered paths (aka files) below
269269
mountPoints, err := d.RuntimeConfig.Mounter.List()
270-
klog.V(4).Infof("[DEBUG] the mount points are %v", mountPoints)
271270
if err != nil {
272271
return fmt.Errorf("error retrieving mountpoints: %v", err)
273272
}

test/e2e/e2e_test.go

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ const (
8585
var (
8686
// default provisioner image used for e2e tests
8787
provisionerImageName = "quay.io/external_storage/local-volume-provisioner:latest"
88-
provisionerImagePullPolicy v1.PullPolicy = "Never"
88+
provisionerImagePullPolicy v1.PullPolicy = "Always"
8989
// storage class volume binding modes
9090
waitMode = storagev1.VolumeBindingWaitForFirstConsumer
9191
immediateMode = storagev1.VolumeBindingImmediate
@@ -232,9 +232,9 @@ var _ = utils.SIGDescribe("PersistentVolumes-local ", func() {
232232
})
233233

234234
AfterEach(func() {
235+
deleteProvisionerDaemonset(config)
235236
cleanupLocalVolumeProvisioner(config)
236237
cleanupStorageClass(config)
237-
deleteProvisionerDaemonset(config)
238238
})
239239

240240
It("should create and recreate local persistent volume", func() {
@@ -290,15 +290,18 @@ var _ = utils.SIGDescribe("PersistentVolumes-local ", func() {
290290
})
291291

292292
AfterEach(func() {
293+
deleteProvisionerDaemonset(config)
293294
cleanupLocalVolumeProvisioner(config)
294295
cleanupStorageClass(config)
295-
deleteProvisionerDaemonset(config)
296296
})
297297

298298
It("should not create local persistent volume for filesystem volume that was not bind mounted", func() {
299299
directoryPath := filepath.Join(config.discoveryDir, "notbindmount")
300300
By("Creating a directory, not bind mounted, in discovery directory")
301301
mkdirCmd := fmt.Sprintf("mkdir -p %v -m 777", directoryPath)
302+
if nodeOSDistroIs("windows") {
303+
mkdirCmd = fmt.Sprintf("mkdir -Force %v", directoryPath)
304+
}
302305
execResult, err := config.hostExec.Execute(mkdirCmd, config.node0)
303306
utils.LogResult(execResult)
304307
Expect(err).NotTo(HaveOccurred())
@@ -313,6 +316,11 @@ var _ = utils.SIGDescribe("PersistentVolumes-local ", func() {
313316
"Error getting logs from pod %s in namespace %s", provisionerPodName, config.ns)
314317

315318
expectedLogMessage := "path \"/mnt/local-storage/notbindmount\" is not an actual mountpoint"
319+
// the expected log message above is thrown in Linux if the mount path doesn't exist in /proc/mounts
320+
// in Windows we instead look for the error `path "%q" fs stats error`
321+
if nodeOSDistroIs("windows") {
322+
expectedLogMessage = `path "c:\\mnt\\local-storage\\notbindmount" fs stats error`
323+
}
316324
Expect(strings.Contains(logs, expectedLogMessage)).To(BeTrue())
317325
})
318326
})
@@ -321,11 +329,19 @@ var _ = utils.SIGDescribe("PersistentVolumes-local ", func() {
321329
Context("Stress with local volume provisioner [Serial]", func() {
322330
var testVols [][]*localVolume
323331

324-
const (
332+
var (
325333
volsPerNode = 10 // Make this non-divisable by volsPerPod to increase changes of partial binding failure
326334
volsPerPod = 3
327335
podsFactor = 4
328336
)
337+
if nodeOSDistroIs("windows") {
338+
// the Windows image is big and having `volsPerNode/volsPerPod + 1` pods pulling it
339+
// at the same time consumes all the bandwidth, in Windows these parameters are
340+
// changed so that the stress test is with fewer parallel pods
341+
volsPerNode = 7
342+
volsPerPod = 3
343+
podsFactor = 3
344+
}
329345

330346
BeforeEach(func() {
331347
setupStorageClass(config, &waitMode)
@@ -343,14 +359,11 @@ var _ = utils.SIGDescribe("PersistentVolumes-local ", func() {
343359
testVols = append(testVols, vols)
344360
}
345361

346-
By("Starting the local volume provisioner")
347362
createProvisionerDaemonset(config)
348363
})
349364

350365
AfterEach(func() {
351-
By("Deleting provisioner daemonset")
352366
deleteProvisionerDaemonset(config)
353-
354367
for i, vols := range testVols {
355368
for _, vol := range vols {
356369
cleanupLocalVolumeProvisionerMountPoint(config, vol, &config.nodes[i])
@@ -393,7 +406,8 @@ var _ = utils.SIGDescribe("PersistentVolumes-local ", func() {
393406
for i := 0; i < numConcurrentPods; i++ {
394407
pvcs := []*v1.PersistentVolumeClaim{}
395408
for j := 0; j < volsPerPod; j++ {
396-
pvc := e2epv.MakePersistentVolumeClaim(makeLocalPVCConfig(config, DirectoryLocalVolumeType), config.ns)
409+
pvcConfig := makeLocalPVCConfig(config, DirectoryLocalVolumeType)
410+
pvc := e2epv.MakePersistentVolumeClaim(pvcConfig, config.ns)
397411
pvc, err := e2epv.CreatePVC(config.client, config.ns, pvc)
398412
framework.ExpectNoError(err)
399413
pvcs = append(pvcs, pvc)
@@ -429,7 +443,8 @@ var _ = utils.SIGDescribe("PersistentVolumes-local ", func() {
429443
}()
430444

431445
By("Waiting for all pods to complete successfully")
432-
err := wait.PollImmediate(time.Second, 5*time.Minute, func() (done bool, err error) {
446+
timeout := 10 * time.Minute
447+
err := wait.PollImmediate(time.Second, timeout, func() (done bool, err error) {
433448
podsList, err := config.client.CoreV1().Pods(config.ns).List(context.TODO(), metav1.ListOptions{})
434449
if err != nil {
435450
return false, err
@@ -475,6 +490,7 @@ func setupStorageClass(config *localTestConfig, mode *storagev1.VolumeBindingMod
475490
}
476491

477492
func cleanupStorageClass(config *localTestConfig) {
493+
By("Cleanup StorageClass")
478494
framework.ExpectNoError(config.client.StorageV1().StorageClasses().Delete(context.TODO(), config.scName, metav1.DeleteOptions{}))
479495
}
480496

@@ -505,6 +521,9 @@ func cleanupLocalVolumeProvisioner(config *localTestConfig) {
505521
for _, node := range config.nodes {
506522
By(fmt.Sprintf("Removing the test discovery directory on node %v", node.Name))
507523
removeCmd := fmt.Sprintf("[ ! -e %v ] || rm -r %v", config.discoveryDir, config.discoveryDir)
524+
if nodeOSDistroIs("windows") {
525+
removeCmd = fmt.Sprintf("rmdir -Recurse -Force %v", config.discoveryDir)
526+
}
508527
execResult, err := config.hostExec.Execute(removeCmd, &node)
509528
utils.LogResult(execResult)
510529
Expect(err).NotTo(HaveOccurred())
@@ -629,8 +648,22 @@ func findLoopDevice(config *localTestConfig, file string, node *v1.Node) string
629648
return strings.TrimSpace(loopDevResult)
630649
}
631650

651+
// normalizePath makes sure the given path is a valid path on Windows too
652+
// by making sure all instances of `/` are replaced with `\\`, and the
653+
// path beings with `c:`
654+
func normalizePath(path string) string {
655+
if !nodeOSDistroIs("windows") {
656+
return path
657+
}
658+
normalizedPath := strings.Replace(path, "/", "\\", -1)
659+
if strings.HasPrefix(normalizedPath, "\\") {
660+
normalizedPath = "c:" + normalizedPath
661+
}
662+
return normalizedPath
663+
}
664+
632665
func setupLocalVolumeProvisionerMountPoint(config *localTestConfig, node *v1.Node, volumeType localVolumeType) *localVolume {
633-
volumePath := path.Join(config.discoveryDir, fmt.Sprintf("vol-%v", string(uuid.NewUUID())))
666+
volumePath := normalizePath(path.Join(config.discoveryDir, fmt.Sprintf("vol-%v", string(uuid.NewUUID()))))
634667
if volumeType == DirectoryLocalVolumeType {
635668
lv := &localVolume{
636669
volumePath: volumePath,
@@ -648,6 +681,7 @@ func setupLocalVolumeProvisionerMountPoint(config *localTestConfig, node *v1.Nod
648681

649682
By(fmt.Sprintf("Mounting local directory at path %q", volumePath))
650683
if nodeOSDistroIs("windows") {
684+
// NOTE: the value must be greater than the PVC config ClaimSize
651685
vhd := setupVHD(config, node, volumePath, 1024*1024*1024 /* 1GB */)
652686
lv.vhd = vhd
653687
} else {
@@ -807,10 +841,7 @@ func createProvisionerDaemonset(config *localTestConfig) {
807841
// mounted as volumes in the pod
808842
// see helm/provisioner/templates/daemonset_windows.yaml for more details
809843
if nodeOSDistroIs("windows") {
810-
apiGroups := []string{
811-
"disk-v1", "volume-v1", "filesystem-v1",
812-
"disk-v1beta2", "volume-v1beta2", "filesystem-v1beta1",
813-
}
844+
apiGroups := []string{"volume-v1", "volume-v1beta2"}
814845

815846
for _, apiGroup := range apiGroups {
816847
additionalVolumes = append(
@@ -1017,7 +1048,7 @@ func createWriteCmd(testDir string, testFile string, writeTestFileContent string
10171048
func createFileDoesntExistCmd(testFileDir string, testFile string) string {
10181049
testFilePath := filepath.Join(testFileDir, testFile)
10191050
if nodeOSDistroIs("windows") {
1020-
return fmt.Sprintf("if(-not(Test-Path -Path %s)) { throw 'File exists' }", testFilePath)
1051+
return fmt.Sprintf("if (Test-Path -Path %s) { throw 'File exists' }", testFilePath)
10211052
}
10221053
return fmt.Sprintf("[ ! -e %s ]", testFilePath)
10231054
}
@@ -1054,6 +1085,7 @@ func (c *localTestConfig) isNodeInList(name string) bool {
10541085
}
10551086

10561087
func deleteProvisionerDaemonset(config *localTestConfig) {
1088+
By("Cleanup Provisioner daemonset")
10571089
ds, err := config.client.AppsV1().DaemonSets(config.ns).Get(context.TODO(), daemonSetName, metav1.GetOptions{})
10581090
if ds == nil {
10591091
return
@@ -1125,6 +1157,7 @@ func makeLocalPVCConfig(config *localTestConfig, volumeType localVolumeType) e2e
11251157
pvcConfig := e2epv.PersistentVolumeClaimConfig{
11261158
AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce},
11271159
StorageClassName: &config.scName,
1160+
ClaimSize: "100M",
11281161
}
11291162
if volumeType == BlockLocalVolumeType {
11301163
pvcVolumeMode := v1.PersistentVolumeBlock

test/e2e/windows/host_exec.go

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,11 @@ import (
2121
"fmt"
2222
"os"
2323
"os/exec"
24+
"strings"
25+
"time"
2426

2527
v1 "k8s.io/api/core/v1"
28+
"k8s.io/apimachinery/pkg/util/wait"
2629
e2estorageutils "k8s.io/kubernetes/test/e2e/storage/utils"
2730
)
2831

@@ -53,21 +56,40 @@ func (h *hostExecutor) Execute(command string, node *v1.Node) (e2estorageutils.R
5356
cmd.Stdout = &outBuffer
5457
cmd.Stderr = &errBuffer
5558

56-
err := cmd.Run()
57-
result := e2estorageutils.Result{
58-
Host: node.Name,
59-
Cmd: cmd.String(),
60-
Stdout: outBuffer.String(),
61-
Stderr: errBuffer.String(),
62-
}
63-
if err != nil {
64-
if exitError, ok := err.(*exec.ExitError); ok {
65-
result.Code = exitError.ExitCode()
59+
var result e2estorageutils.Result
60+
61+
// sometimes `gcloud compute ssh` fails with
62+
//
63+
// Permission denied (publickey,keyboard-interactive).
64+
// ERROR: (gcloud.compute.ssh) [/usr/bin/ssh] exited with return code [255]
65+
//
66+
// in that case let's retry with backoff
67+
backoff := wait.Backoff{Duration: 1 * time.Second, Factor: 1, Steps: 3}
68+
err := wait.ExponentialBackoff(backoff, func() (bool, error) {
69+
err := cmd.Run()
70+
result = e2estorageutils.Result{
71+
Host: node.Name,
72+
Cmd: cmd.String(),
73+
Stdout: outBuffer.String(),
74+
Stderr: errBuffer.String(),
6675
}
67-
return result, err
68-
}
76+
if err != nil {
77+
if strings.Contains(result.Stderr, "Permission denied") {
78+
return false, nil
79+
}
80+
81+
// the command failed with an error that's not transient
82+
if exitError, ok := err.(*exec.ExitError); ok {
83+
result.Code = exitError.ExitCode()
84+
}
85+
return true, err
86+
}
87+
88+
// request succeeded!
89+
return true, nil
90+
})
6991

70-
return result, nil
92+
return result, err
7193
}
7294

7395
// IssueCommandWithResult issues command on the given node and returns stdout as

test/e2e/windows/vhd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func NewVHD(path string, sizeBytes int) *VHD {
4141
func (vhd *VHD) StageScript() (string, error) {
4242
script := strings.Replace(`"& {
4343
$global:progressPreference = 'SilentlyContinue'
44-
$vhdPath = {{.Path}}
44+
$vhdPath = '{{.Path}}'
4545
New-VHD -Path $vhdPath -SizeBytes {{.SizeBytes}}
4646
Mount-VHD -Path $vhdPath -PassThru | Initialize-Disk -PartitionStyle GPT -PassThru | New-Partition -UseMaximumSize
4747
Get-VHD -Path $vhdPath | Get-Partition | Get-Volume | Format-Volume -Filesystem ntfs -Confirm:$false

0 commit comments

Comments
 (0)