Merge pull request #4853 from travisn/test-focus-csi

Focus integration tests on the CSI driver and less on Flex
This commit is contained in:
Sébastien Han authored and GitHub committed 2020-02-18 14:34:46 +01:00
commit 220ffbc07c
41 files changed
+833 -1836

No files matched your search

-2
View File
@@ -55,7 +55,6 @@ SERVER_PACKAGES = $(GO_PROJECT)/cmd/rook $(GO_PROJECT)/cmd/rookflex
# tests packages that will be compiled into binaries
TEST_PACKAGES = $(GO_PROJECT)/tests/integration
LONGHAUL_TEST_PACKAGES = $(GO_PROJECT)/tests/longhaul
# the root go project
GO_PROJECT=github.com/rook/rook
@@ -80,7 +79,6 @@ GO_LDFLAGS=$(LDFLAGS)
GO_TAGS=$(TAGS)
GO_TEST_PACKAGES=$(TEST_PACKAGES)
GO_LONGHAUL_TEST_PACKAGES=$(LONGHAUL_TEST_PACKAGES)
GO_TEST_FLAGS=$(TESTFLAGS)
GO_TEST_SUITE=$(SUITE)
GO_TEST_FILTER=$(TESTFILTER)
+1 -1
View File
@@ -127,7 +127,7 @@ go.init: go.vendor.lite
go.build:
@echo === go build $(PLATFORM)
$(foreach p,$(GO_STATIC_PACKAGES),@CGO_ENABLED=0 $(GO) build -v -i -o $(GO_OUT_DIR)/$(lastword $(subst /, ,$(p)))$(GO_OUT_EXT) $(GO_STATIC_FLAGS) $(p)${\n})
$(foreach p,$(GO_TEST_PACKAGES) $(GO_LONGHAUL_TEST_PACKAGES),@CGO_ENABLED=0 $(GO) test -v -i -c -o $(GO_TEST_OUTPUT)/$(lastword $(subst /, ,$(p)))$(GO_OUT_EXT) $(GO_STATIC_FLAGS) $(p)${\n})
$(foreach p,$(GO_TEST_PACKAGES),@CGO_ENABLED=0 $(GO) test -v -i -c -o $(GO_TEST_OUTPUT)/$(lastword $(subst /, ,$(p)))$(GO_OUT_EXT) $(GO_STATIC_FLAGS) $(p)${\n})
.PHONY: go.install
go.install:
+1 -1
View File
@@ -313,7 +313,7 @@ func (c *cluster) doOrchestration(rookImage string, cephVersion cephver.CephVers
// Notify the child controllers that the cluster spec might have changed
logger.Debug("notifying CR child of the potential upgrade")
for _, child := range c.childControllers {
child.ParentClusterChanged(*c.Spec, c.Info, c.isUpgrade)
go child.ParentClusterChanged(*c.Spec, c.Info, c.isUpgrade)
}
return nil
+5 -1
View File
@@ -1031,7 +1031,11 @@ func (c *ClusterController) removeFinalizer(obj interface{}) {
// Get the latest cluster instead of using the same instance in case it has been changed
cluster, err := c.context.RookClientset.CephV1().CephClusters(cl.Namespace).Get(cl.Name, metav1.GetOptions{})
if err != nil {
logger.Errorf("failed to remove finalizer. failed to get cluster. %v", err)
if kerrors.IsNotFound(err) {
logger.Errorf("cluster was removed, no need to remove finalizer")
} else {
logger.Errorf("failed to remove finalizer. failed to get cluster. %v", err)
}
return
}
objectMeta := &cluster.ObjectMeta
+1
View File
@@ -170,6 +170,7 @@ func (c *FilesystemController) ParentClusterChanged(cluster cephv1.ClusterSpec,
return
}
logger.Infof("waiting for the orchestration lock to update the filesystem")
c.acquireOrchestrationLock()
defer c.releaseOrchestrationLock()
+1
View File
@@ -163,6 +163,7 @@ func (c *CephNFSController) ParentClusterChanged(cluster cephv1.ClusterSpec, clu
return
}
logger.Infof("waiting for the orchestration lock to update the nfs daemons")
c.acquireOrchestrationLock()
defer c.releaseOrchestrationLock()
+1
View File
@@ -196,6 +196,7 @@ func (c *ObjectStoreController) ParentClusterChanged(cluster cephv1.ClusterSpec,
return
}
logger.Infof("waiting for the orchestration lock to update the object store")
c.acquireOrchestrationLock()
defer c.releaseOrchestrationLock()
+4 -2
View File
@@ -21,7 +21,6 @@ import (
"fmt"
"time"
"k8s.io/api/batch/v1"
batch "k8s.io/api/batch/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -91,6 +90,9 @@ func DeleteBatchJob(clientset kubernetes.Interface, namespace, name string, wait
options := &metav1.DeleteOptions{GracePeriodSeconds: &gracePeriod, PropagationPolicy: &propagation}
if err := clientset.BatchV1().Jobs(namespace).Delete(name, options); err != nil {
if errors.IsNotFound(err) {
return nil
}
return fmt.Errorf("failed to remove previous provisioning job for node %s. %+v", name, err)
}
@@ -117,7 +119,7 @@ func DeleteBatchJob(clientset kubernetes.Interface, namespace, name string, wait
// AddRookVersionLabelToJob adds or updates a label reporting the Rook version which last
// modified a Job.
func AddRookVersionLabelToJob(j *v1.Job) {
func AddRookVersionLabelToJob(j *batch.Job) {
if j == nil {
return
}
+5 -42
View File
@@ -103,12 +103,11 @@ _output/tests/${platform}/integration/integration -test.v
### Test parameters
In addition to standard go tests parameters, the following custom parameters are available while running tests:
| Parameter | Description | Possible values | Default |
| ----------------- | -------------------------------------------- | ---------------- | ----------------- |
| rook_platform | platform Rook needs to be installed on | kubernetes | kubernetes |
| k8s_version | version of Kubernetes to be installed | v1.10+ | v1.13.1 |
| rook_image | Rook image name to be installed | valid image name | rook/ceph |
| skip_install_rook | skips installing Rook (if already installed) | true or false | false |
| Parameter | Description | Possible values | Default |
| ------------- | -------------------------------------- | ---------------- | ---------- |
| rook_platform | platform Rook needs to be installed on | kubernetes | kubernetes |
| k8s_version | version of Kubernetes to be installed | v1.10+ | v1.13.1 |
| rook_image | Rook image name to be installed | valid image name | rook/ceph |
### Running Tests with parameters.
#### To run all integration tests run
@@ -125,39 +124,3 @@ go test -v -timeout 1800s -run SmokeSuite github.com/rook/rook/tests/integration
```
go test -v -timeout 1800s -run SmokeSuite github.com/rook/rook/tests/integration -testify.m TestRookClusterInstallation_SmokeTest
```
##### To run specific without installing rook
```
go test -v -timeout 1800s -run SmokeSuite github.com/rook/rook/tests/integration --skip_install_rook
```
If the `skip_install_rook` flag is set to true, then Rook is not uninstalled either.
#### Run Longhaul Tests
[Longhaul](/tests/block/k8s/longhaul) tests are integration tests that run for extended period of time. A load profile can be configured
using the following load test flags
| Parameter | Description | Possible values | Default |
| ------------------ | ------------------------------------------------- | ----------------------- | ------- |
| load_parallel_runs | performs concurrent operations | any number | 20 |
| load_volumes | number of volumes | >1 | 1 |
| load_time | number of seconds to run | >1 | 1800 |
| load_size | size of load profile (3M, 10M, or 50M per thread) | small, medium, or large | medium |
| enable_chaos | kill random pods in Rook cluster | true or false | false |
e.g.
```
go test -run TestObjectLongHaul github.com/rook/rook/tests/longhaul --load_parallel_runs=20 --load_time 1800 --load_size small --load_volumes 3
```
The longhaul test just like other test is going to install Rook if it's not already installed, but it is not going to clean up test data or uninstall Rook after the run.
Longhaul test is designed to run multiple times on the same setup and installation of Rook to tests its stability. Test data and Rook should be cleaned up manually after the test.
You can measure memory, CPU, IOPS, throughput, and other settings on a cluster using Prometheus. The metrics collected during load test can be visualize using Grafana.
Here a couple of helpful links to get prometheus and grafana started and collect metrics:
[kube-prometheus](https://github.com/coreos/prometheus-operator/tree/master/contrib/kube-prometheus) and [cluster-deploy-script](https://github.com/coreos/prometheus-operator/blob/master/contrib/kube-prometheus/hack/cluster-monitoring/deploy)
**Prerequisites**:
* Go installed and GO_PATH set
* Dep installed
* Wget installed
* When running tests locally, make sure `kubectl` is accessible globally in your `PATH` as the test framework uses `kubectl`
+24 -28
View File
@@ -22,6 +22,7 @@ import (
"github.com/rook/rook/pkg/daemon/ceph/client"
"github.com/rook/rook/tests/framework/installer"
"github.com/rook/rook/tests/framework/utils"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// BlockOperation is wrapper for k8s rook block operations
@@ -38,11 +39,6 @@ type BlockImage struct {
MountPoint string `json:"mountPoint"`
}
var (
writeDataToBlockPod = []string{"sh", "-c", "WRITE_DATA_CMD"}
readDataFromBlockPod = []string{"cat", "READ_DATA_CMD"}
)
// CreateBlockOperation - Constructor to create BlockOperation - client to perform rook Block operations on k8s
func CreateBlockOperation(k8shelp *utils.K8sHelper, manifests installer.CephManifests) *BlockOperation {
return &BlockOperation{k8shelp, manifests}
@@ -64,22 +60,32 @@ func (b *BlockOperation) Create(manifest string, size int) (string, error) {
}
func (b *BlockOperation) CreatePvc(claimName, storageClassName, mode, size string) error {
return b.k8sClient.ResourceOperation("apply", b.manifests.GetBlockPvcDef(claimName, storageClassName, mode, size))
func (b *BlockOperation) CreateStorageClassAndPVC(csi bool, pvcNamespace, clusterNamespace, systemNamespace, poolName, storageClassName, reclaimPolicy, blockName, mode string) error {
if err := b.k8sClient.ResourceOperation("apply", b.manifests.GetBlockPoolDef(poolName, clusterNamespace, "1")); err != nil {
return err
}
if err := b.k8sClient.ResourceOperation("apply", b.manifests.GetBlockStorageClassDef(csi, poolName, storageClassName, reclaimPolicy, clusterNamespace, systemNamespace)); err != nil {
return err
}
return b.k8sClient.ResourceOperation("apply", b.manifests.GetBlockPVCDef(blockName, pvcNamespace, storageClassName, mode, "1M"))
}
func (b *BlockOperation) CreateStorageClass(poolName, storageClassName, reclaimPolicy, namespace string, varClusterName bool) error {
return b.k8sClient.ResourceOperation("apply", b.manifests.GetBlockStorageClassDef(poolName, storageClassName, reclaimPolicy, namespace, varClusterName))
func (b *BlockOperation) CreatePVC(namespace, claimName, storageClassName, mode, size string) error {
return b.k8sClient.ResourceOperation("apply", b.manifests.GetBlockPVCDef(claimName, namespace, storageClassName, mode, size))
}
func (b *BlockOperation) DeletePvc(claimName, storageClassName, mode, size string) error {
err := b.k8sClient.ResourceOperation("delete", b.manifests.GetBlockPvcDef(claimName, storageClassName, mode, size))
return err
func (b *BlockOperation) CreateStorageClass(csi bool, poolName, storageClassName, reclaimPolicy, namespace string) error {
return b.k8sClient.ResourceOperation("apply", b.manifests.GetBlockStorageClassDef(csi, poolName, storageClassName, reclaimPolicy, namespace, installer.SystemNamespace(namespace)))
}
func (b *BlockOperation) DeleteStorageClass(poolName, storageClassName, reclaimPolicy, namespace string) error {
err := b.k8sClient.ResourceOperation("delete", b.manifests.GetBlockStorageClassDef(poolName, storageClassName, reclaimPolicy, namespace, false))
return err
func (b *BlockOperation) DeletePVC(namespace, claimName string) error {
logger.Infof("deleting pvc %q from namespace %q", claimName, namespace)
return b.k8sClient.Clientset.CoreV1().PersistentVolumeClaims(namespace).Delete(claimName, &metav1.DeleteOptions{})
}
func (b *BlockOperation) DeleteStorageClass(storageClassName string) error {
logger.Infof("deleting storage class %q", storageClassName)
return b.k8sClient.Clientset.StorageV1().StorageClasses().Delete(storageClassName, &metav1.DeleteOptions{})
}
// BlockDelete Function to delete a Block using Rook
@@ -134,17 +140,7 @@ func (b *BlockOperation) DeleteBlockImage(image BlockImage, namespace string) er
return client.DeleteImage(context, namespace, image.Name, image.PoolName)
}
// BlockMap Function to map a Block using Rook
// Input parameters -
// manifest - Pod definition - pod should be defined to use a pvc that was created earlier
// Output - k8s create pod operation output and/or error
func (b *BlockOperation) BlockMap(manifest string) (string, error) {
args := []string{"apply", "-f", "-"}
result, err := b.k8sClient.KubectlWithStdin(manifest, args...)
if err != nil {
return "", fmt.Errorf("Unable to map block -- : %s", err)
}
return result, nil
// CreateClientPod starts a pod that should have a block PVC.
func (b *BlockOperation) CreateClientPod(manifest string) error {
return b.k8sClient.ResourceOperation("apply", manifest)
}
+5
View File
@@ -55,6 +55,11 @@ func (f *FilesystemOperation) Create(name, namespace string, activeCount int) er
return nil
}
// CreateStorageClass creates a storage class for CephFS clients
func (f *FilesystemOperation) CreateStorageClass(fsName, namespace, storageClassName string) error {
return f.k8sh.ResourceOperation("apply", f.manifests.GetFileStorageClassDef(fsName, storageClassName, namespace))
}
// ScaleDown scales down the number of active metadata servers of a filesystem in Rook
func (f *FilesystemOperation) ScaleDown(name, namespace string) error {
logger.Infof("scaling down the number of filesystem active metadata servers via CRD")
+1 -16
View File
@@ -109,30 +109,15 @@ func (p *PoolOperation) CephPoolExists(namespace, name string) (bool, error) {
return false, nil
}
func (p *PoolOperation) CreateStorageClassAndPvc(namespace, poolName, storageClassName, reclaimPolicy, blockName, mode string) error {
return p.k8sh.ResourceOperation("apply", p.manifests.GetBlockPoolStorageClassAndPvcDef(namespace, poolName, storageClassName, reclaimPolicy, blockName, mode))
}
func (p *PoolOperation) DeleteStorageClass(storageClassName string) error {
return p.k8sh.Clientset.StorageV1().StorageClasses().Delete(storageClassName, &metav1.DeleteOptions{})
}
func (p *PoolOperation) DeletePool(blockClient *BlockOperation, namespace, poolName string) error {
// Delete all the images in a pool
blockImagesList, _ := blockClient.List(namespace)
for _, blockImage := range blockImagesList {
if poolName == blockImage.PoolName {
logger.Infof("force deleting block image %q in pool %q", blockImage, poolName)
blockClient.DeleteBlockImage(blockImage, namespace)
}
}
return p.k8sh.RookClientset.CephV1().CephBlockPools(namespace).Delete(poolName, &metav1.DeleteOptions{})
}
func (p *PoolOperation) DeletePvc(namespace, pvcName string) error {
return p.k8sh.Clientset.CoreV1().PersistentVolumeClaims(namespace).Delete(pvcName, &metav1.DeleteOptions{})
}
func (p *PoolOperation) CreateStorageClass(namespace, poolName, storageClassName, reclaimPolicy string) error {
return p.k8sh.ResourceOperation("apply", p.manifests.GetBlockPoolStorageClass(namespace, poolName, storageClassName, reclaimPolicy))
}
+56 -74
View File
@@ -23,7 +23,6 @@ import (
"math/rand"
"os"
"path"
"strings"
"testing"
"time"
@@ -50,8 +49,9 @@ const (
)
var (
MimicVersion = cephv1.CephVersionSpec{Image: mimicTestImage}
NautilusVersion = cephv1.CephVersionSpec{Image: nautilusTestImage}
MimicVersion = cephv1.CephVersionSpec{Image: mimicTestImage}
NautilusVersion = cephv1.CephVersionSpec{Image: nautilusTestImage}
globalTestJobIndex = 0
)
// CephInstaller wraps installing and uninstalling rook on a platform
@@ -67,49 +67,6 @@ type CephInstaller struct {
T func() *testing.T
}
func (h *CephInstaller) CreateCephCRDs() error {
var resources string
logger.Info("Creating Rook CRDs")
resources = h.Manifests.GetRookCRDs()
var err error
for i := 0; i < 5; i++ {
if i > 0 {
logger.Infof("waiting 10s...")
time.Sleep(10 * time.Second)
}
_, err = h.k8shelper.KubectlWithStdin(resources, createFromStdinArgs...)
if err == nil {
return nil
}
// If the CRD already exists, the previous test must not have completed cleanup yet.
// Delete the CRDs and attempt to wait for the cleanup.
if strings.Index(err.Error(), "AlreadyExists") == -1 {
return err
}
// ensure all the cluster CRDs are removed
if err = h.purgeClusters(); err != nil {
logger.Warningf("could not purge cluster crds. %+v", err)
}
// remove the finalizer from the cluster CRD
if _, err := h.k8shelper.Kubectl("patch", "crd", "cephclusters.ceph.rook.io", "-p", `{"metadata":{"finalizers": []}}`, "--type=merge"); err != nil {
logger.Warningf("could not remove finalizer from cluster crd. %+v", err)
}
logger.Warningf("CRDs were not cleaned up from a previous test. Deleting them to try again...")
if _, err := h.k8shelper.KubectlWithStdin(resources, deleteFromStdinArgs...); err != nil {
logger.Infof("deleting the crds returned an error: %+v", err)
}
}
return err
}
// CreateCephOperator creates rook-operator via kubectl
func (h *CephInstaller) CreateCephOperator(namespace string) (err error) {
logger.Infof("Starting Rook Operator")
@@ -117,7 +74,9 @@ func (h *CephInstaller) CreateCephOperator(namespace string) (err error) {
h.k8shelper.CreateAnonSystemClusterBinding()
// creating rook resources
if err = h.CreateCephCRDs(); err != nil {
logger.Info("Creating Rook CRDs")
resources := h.Manifests.GetRookCRDs()
if _, err = h.k8shelper.KubectlWithStdin(resources, createFromStdinArgs...); err != nil {
return err
}
@@ -126,11 +85,19 @@ func (h *CephInstaller) CreateCephOperator(namespace string) (err error) {
h.k8shelper.ChangeHostnames()
}
rookOperator := h.Manifests.GetRookOperator(namespace)
err = h.k8shelper.CreateNamespace(namespace)
if err != nil {
if errors.IsAlreadyExists(err) {
logger.Warningf("Namespace %q already exists!!!", namespace)
} else {
return fmt.Errorf("failed to create namespace %q. %v", namespace, err)
}
}
rookOperator := h.Manifests.GetRookOperator(namespace)
_, err = h.k8shelper.KubectlWithStdin(rookOperator, createFromStdinArgs...)
if err != nil {
return fmt.Errorf("Failed to create rook-operator pod : %v ", err)
return fmt.Errorf("Failed to create rook-operator pod: %v ", err)
}
logger.Infof("Rook Operator started")
@@ -206,7 +173,10 @@ func (h *CephInstaller) CreateK8sRookClusterWithHostPathAndDevicesOrPVC(namespac
}
if err := h.WipeClusterDisks(namespace); err != nil {
return fmt.Errorf("failed to wipe cluster disks. %+v", err)
logger.Warningf("failed to wipe cluster disks. %+v. trying again...", err)
if err = h.WipeClusterDisks(namespace); err != nil {
return fmt.Errorf("failed to wipe cluster disks. %+v", err)
}
}
logger.Infof("Starting Rook Cluster with yaml")
@@ -382,11 +352,6 @@ func (h *CephInstaller) InstallRookOnK8sWithHostPathAndDevicesOrPVC(namespace, s
mon cephv1.MonSpec, startWithAllNodes bool, rbdMirrorWorkers int) (bool, error) {
var err error
// flag used for local debugging purpose, when rook is pre-installed
if Env.SkipInstallRook {
return true, nil
}
k8sversion := h.k8shelper.GetK8sServerVersion()
logger.Infof("Installing rook on k8s %s", k8sversion)
@@ -455,10 +420,6 @@ func (h *CephInstaller) UninstallRook(namespace string, gatherLogs bool) {
// UninstallRookFromMultipleNS uninstalls rook from multiple namespaces in k8s
func (h *CephInstaller) UninstallRookFromMultipleNS(gatherLogs bool, systemNamespace string, namespaces ...string) {
// flag used for local debugging purpose, when rook is pre-installed
if Env.SkipInstallRook {
return
}
if gatherLogs {
// Gather logs after status checks
h.GatherAllRookLogs(h.T().Name(), append([]string{systemNamespace}, namespaces...)...)
@@ -495,6 +456,9 @@ func (h *CephInstaller) UninstallRookFromMultipleNS(gatherLogs bool, systemNames
checkError(h.T(), err, fmt.Sprintf("cannot delete namespace %s", namespace))
}
err = h.k8shelper.DeleteResourceAndWait(false, "namespace", systemNamespace)
checkError(h.T(), err, fmt.Sprintf("cannot delete system namespace %s", systemNamespace))
logger.Infof("removing the operator from namespace %s", systemNamespace)
err = h.k8shelper.DeleteResource(
"crd",
@@ -513,8 +477,10 @@ func (h *CephInstaller) UninstallRookFromMultipleNS(gatherLogs bool, systemNames
if h.useHelm {
err = h.helmHelper.DeleteLocalRookHelmChart(helmDeployName)
} else {
logger.Infof("Deleting all the resources in the operator manifest")
rookOperator := h.Manifests.GetRookOperator(systemNamespace)
_, err = h.k8shelper.KubectlWithStdin(rookOperator, deleteFromStdinArgs...)
logger.Infof("DONE deleting all the resources in the operator manifest")
}
checkError(h.T(), err, "cannot uninstall rook-operator")
@@ -575,6 +541,17 @@ func (h *CephInstaller) UninstallRookFromMultipleNS(gatherLogs bool, systemNames
// revert the hostname labels for the test
h.k8shelper.RestoreHostnames()
}
// wait a bit longer for the system namespace to be cleaned up after their deletion
for i := 0; i < 15; i++ {
_, err := h.k8shelper.Clientset.CoreV1().Namespaces().Get(systemNamespace, metav1.GetOptions{})
if err != nil && errors.IsNotFound(err) {
logger.Infof("system namespace %q removed", systemNamespace)
break
}
logger.Infof("system namespace %q still found...", systemNamespace)
time.Sleep(5 * time.Second)
}
}
func (h *CephInstaller) removeClusterFinalizers(namespace, name string) {
@@ -710,17 +687,18 @@ func NewCephInstaller(t func() *testing.T, clientset *kubernetes.Clientset, useH
// WipeClusterDisks runs a disk wipe job on all nodes in the k8s cluster.
func (h *CephInstaller) WipeClusterDisks(namespace string) error {
wipeJobName := func(node string) string {
return k8sutil.TruncateNodeName("rook-ceph-disk-wipe-%s", node)
}
// Wipe clean disks on all nodes
nodes, err := h.GetNodeHostnames()
if err != nil {
return fmt.Errorf("failed to get node hostnames. %+v", err)
}
var jobNames []string
for _, node := range nodes {
job := h.GetDiskWipeJob(node, wipeJobName(node), namespace)
// Start the new job
globalTestJobIndex++
jobName := fmt.Sprintf("rook-ceph-disk-wipe-%d", globalTestJobIndex)
jobNames = append(jobNames, jobName)
job := h.GetDiskWipeJob(node, jobName, namespace)
_, err := h.k8shelper.KubectlWithStdin(job, createFromStdinArgs...)
if err != nil {
return fmt.Errorf("failed to create disk wipe job for host %s. %+v", node, err)
@@ -728,13 +706,13 @@ func (h *CephInstaller) WipeClusterDisks(namespace string) error {
}
allJobsAreComplete := func() (done bool, err error) {
for _, node := range nodes {
j, err := h.k8shelper.Clientset.BatchV1().Jobs(namespace).Get(wipeJobName(node), metav1.GetOptions{})
for _, jobName := range jobNames {
j, err := h.k8shelper.Clientset.BatchV1().Jobs(namespace).Get(jobName, metav1.GetOptions{})
if err != nil {
return false, nil
}
if j.Status.Failed > 0 {
return false, fmt.Errorf("job %s failed", wipeJobName(node))
return false, fmt.Errorf("job %s failed", jobName)
}
if j.Status.Succeeded == 0 {
return false, nil
@@ -743,15 +721,19 @@ func (h *CephInstaller) WipeClusterDisks(namespace string) error {
return true, nil
}
if err = wait.Poll(5*time.Second, 90*time.Second, allJobsAreComplete); err != nil {
// return the error below after cleaning up the jobs
err = wait.Poll(5*time.Second, 90*time.Second, allJobsAreComplete)
// delete the jobs
for _, jobName := range jobNames {
// if delete fails, don't worry about the error; delete only on best-effort basis
wait := false
k8sutil.DeleteBatchJob(h.k8shelper.Clientset, namespace, jobName, wait)
}
if err != nil {
return fmt.Errorf("failed to wait for wipe jobs to complete. %+v", err)
}
for _, node := range nodes {
// if delete fails, don't worry about the error; delete only on best-effort basis
h.k8shelper.Clientset.BatchV1().Jobs(namespace).Delete(wipeJobName(node), &metav1.DeleteOptions{})
}
return nil
}
+50 -29
View File
@@ -39,18 +39,17 @@ type CephManifests interface {
GetRookExternalCluster(settings *ClusterExternalSettings) string
GetRookToolBox(namespace string) string
GetCleanupPod(node, removalDir string) string
GetBlockPoolDef(poolName string, namespace string, replicaSize string) string
GetBlockStorageClassDef(poolName string, storageClassName string, reclaimPolicy string, namespace string, varClusterName bool) string
GetBlockPvcDef(claimName string, storageClassName string, accessModes string, size string) string
GetBlockPoolStorageClassAndPvcDef(namespace string, poolName string, storageClassName string, reclaimPolicy string, blockName string, accessMode string) string
GetBlockPoolStorageClass(namespace string, poolName string, storageClassName string, reclaimPolicy string) string
GetBlockPoolDef(poolName, namespace, replicaSize string) string
GetBlockStorageClassDef(csi bool, poolName, storageClassName, reclaimPolicy, namespace, systemNamespace string) string
GetFileStorageClassDef(fsName, storageClassName, namespace string) string
GetBlockPVCDef(claimName, namespace, storageClassName, accessModes, size string) string
GetFilesystem(namepace, name string, activeCount int) string
GetNFS(namepace, name, pool string, daemonCount int) string
GetObjectStore(namespace, name string, replicaCount, port int) string
GetObjectStoreUser(namespace, name string, displayName string, store string) string
GetBucketStorageClass(namespace string, storeName string, storageClassName string, reclaimPolicy string, region string) string
GetObc(obcName string, storageClassName string, bucketName string, createBucket bool) string
GetClient(namespace string, name string, caps map[string]string) string
GetObjectStoreUser(namespace, name, displayName, store string) string
GetBucketStorageClass(namespace, storeName, storageClassName, reclaimPolicy, region string) string
GetObc(obcName, storageClassName, bucketName string, createBucket bool) string
GetClient(namespace, name string, caps map[string]string) string
}
type ClusterSettings struct {
@@ -584,11 +583,7 @@ spec:
// GetRookOperator returns rook Operator manifest
func (m *CephManifestsMaster) GetRookOperator(namespace string) string {
return `kind: Namespace
apiVersion: v1
metadata:
name: ` + namespace + `
---
return `
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
@@ -2000,11 +1995,26 @@ spec:
targetSizeRatio: .5`
}
func (m *CephManifestsMaster) GetBlockStorageClassDef(poolName string, storageClassName string, reclaimPolicy string, namespace string, varClusterName bool) string {
namespaceParameter := "clusterNamespace"
if varClusterName {
namespaceParameter = "clusterName"
func (m *CephManifestsMaster) GetBlockStorageClassDef(csi bool, poolName, storageClassName, reclaimPolicy, namespace, systemNamespace string) string {
// Create a CSI driver storage class
if csi {
return `
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ` + storageClassName + `
provisioner: ` + systemNamespace + `.rbd.csi.ceph.com
reclaimPolicy: ` + reclaimPolicy + `
parameters:
pool: ` + poolName + `
clusterID: ` + namespace + `
csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner
csi.storage.k8s.io/provisioner-secret-namespace: ` + namespace + `
csi.storage.k8s.io/node-stage-secret-name: rook-csi-rbd-node
csi.storage.k8s.io/node-stage-secret-namespace: ` + namespace + `
`
}
// Create a FLEX driver storage class
return `apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
@@ -2014,14 +2024,34 @@ allowVolumeExpansion: true
reclaimPolicy: ` + reclaimPolicy + `
parameters:
blockPool: ` + poolName + `
` + namespaceParameter + `: ` + namespace
clusterNamespace: ` + namespace
}
func (m *CephManifestsMaster) GetBlockPvcDef(claimName, storageClassName, accessModes, size string) string {
func (m *CephManifestsMaster) GetFileStorageClassDef(fsName, storageClassName, namespace string) string {
// Create a CSI driver storage class
return `
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ` + storageClassName + `
provisioner: ` + SystemNamespace(namespace) + `.cephfs.csi.ceph.com
parameters:
clusterID: ` + namespace + `
fsName: ` + fsName + `
pool: ` + fsName + `-data0
csi.storage.k8s.io/provisioner-secret-name: rook-csi-cephfs-provisioner
csi.storage.k8s.io/provisioner-secret-namespace: ` + namespace + `
csi.storage.k8s.io/node-stage-secret-name: rook-csi-cephfs-node
csi.storage.k8s.io/node-stage-secret-namespace: ` + namespace + `
`
}
func (m *CephManifestsMaster) GetBlockPVCDef(claimName, namespace, storageClassName, accessModes, size string) string {
return `apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ` + claimName + `
namespace: ` + namespace + `
annotations:
volume.beta.kubernetes.io/storage-class: ` + storageClassName + `
spec:
@@ -2032,15 +2062,6 @@ spec:
storage: ` + size
}
func (m *CephManifestsMaster) GetBlockPoolStorageClassAndPvcDef(namespace string, poolName string, storageClassName string, reclaimPolicy string, blockName string, accessMode string) string {
return concatYaml(m.GetBlockPoolDef(poolName, namespace, "1"),
concatYaml(m.GetBlockStorageClassDef(poolName, storageClassName, reclaimPolicy, namespace, false), m.GetBlockPvcDef(blockName, storageClassName, accessMode, "1M")))
}
func (m *CephManifestsMaster) GetBlockPoolStorageClass(namespace string, poolName string, storageClassName string, reclaimPolicy string) string {
return concatYaml(m.GetBlockPoolDef(poolName, namespace, "1"), m.GetBlockStorageClassDef(poolName, storageClassName, reclaimPolicy, namespace, false))
}
// GetFilesystem returns the manifest to create a Rook filesystem resource with the given config.
func (m *CephManifestsMaster) GetFilesystem(namespace, name string, activeCount int) string {
return `apiVersion: ceph.rook.io/v1
@@ -447,11 +447,7 @@ spec:
// GetRookOperator returns rook Operator manifest
func (m *CephManifestsV1_1) GetRookOperator(namespace string) string {
return `kind: Namespace
apiVersion: v1
metadata:
name: ` + namespace + `
---
return `
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
@@ -1712,11 +1708,25 @@ spec:
size: ` + replicaSize
}
func (m *CephManifestsV1_1) GetBlockStorageClassDef(poolName string, storageClassName string, reclaimPolicy string, namespace string, varClusterName bool) string {
namespaceParameter := "clusterNamespace"
if varClusterName {
namespaceParameter = "clusterName"
func (m *CephManifestsV1_1) GetBlockStorageClassDef(csi bool, poolName, storageClassName, reclaimPolicy, namespace, systemNamespace string) string {
// Create a CSI driver storage class
if csi {
return `
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ` + storageClassName + `
provisioner: ` + systemNamespace + `.rbd.csi.ceph.com
parameters:
pool: ` + poolName + `
clusterID: ` + namespace + `
csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner
csi.storage.k8s.io/provisioner-secret-namespace: ` + namespace + `
csi.storage.k8s.io/node-stage-secret-name: rook-csi-rbd-node
csi.storage.k8s.io/node-stage-secret-namespace: ` + namespace + `
`
}
// Create a FLEX driver storage class
return `apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
@@ -1726,14 +1736,36 @@ allowVolumeExpansion: true
reclaimPolicy: ` + reclaimPolicy + `
parameters:
blockPool: ` + poolName + `
` + namespaceParameter + `: ` + namespace
clusterNamespace: ` + namespace
}
func (m *CephManifestsV1_1) GetBlockPvcDef(claimName, storageClassName, accessModes, size string) string {
func (m *CephManifestsV1_1) GetFileStorageClassDef(fsName, storageClassName, namespace string) string {
// Create a CSI driver storage class
csiCephFSNodeSecret := "rook-csi-cephfs-node"
csiCephFSProvisionerSecret := "rook-csi-cephfs-provisioner"
return `
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ` + storageClassName + `
provisioner: ` + SystemNamespace(namespace) + `.cephfs.csi.ceph.com
parameters:
clusterID: ` + namespace + `
fsName: ` + fsName + `
pool: ` + fsName + `-data0
csi.storage.k8s.io/provisioner-secret-name: ` + csiCephFSProvisionerSecret + `
csi.storage.k8s.io/provisioner-secret-namespace: ` + namespace + `
csi.storage.k8s.io/node-stage-secret-name: ` + csiCephFSNodeSecret + `
csi.storage.k8s.io/node-stage-secret-namespace: ` + namespace + `
`
}
func (m *CephManifestsV1_1) GetBlockPVCDef(claimName, namespace, storageClassName, accessModes, size string) string {
return `apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ` + claimName + `
namespace: ` + namespace + `
annotations:
volume.beta.kubernetes.io/storage-class: ` + storageClassName + `
spec:
@@ -1744,15 +1776,6 @@ spec:
storage: ` + size
}
func (m *CephManifestsV1_1) GetBlockPoolStorageClassAndPvcDef(namespace string, poolName string, storageClassName string, reclaimPolicy string, blockName string, accessMode string) string {
return concatYaml(m.GetBlockPoolDef(poolName, namespace, "1"),
concatYaml(m.GetBlockStorageClassDef(poolName, storageClassName, reclaimPolicy, namespace, false), m.GetBlockPvcDef(blockName, storageClassName, accessMode, "1M")))
}
func (m *CephManifestsV1_1) GetBlockPoolStorageClass(namespace string, poolName string, storageClassName string, reclaimPolicy string) string {
return concatYaml(m.GetBlockPoolDef(poolName, namespace, "1"), m.GetBlockStorageClassDef(poolName, storageClassName, reclaimPolicy, namespace, false))
}
// GetFilesystem returns the manifest to create a Rook filesystem resource with the given config.
func (m *CephManifestsV1_1) GetFilesystem(namespace, name string, activeCount int) string {
return `apiVersion: ceph.rook.io/v1
-2
View File
@@ -27,7 +27,6 @@ type EnvironmentManifest struct {
RookImageName string
ToolboxImageName string
BaseTestDir string
SkipInstallRook bool
LoadVolumeNumber int
LoadConcurrentRuns int
LoadTime int
@@ -45,7 +44,6 @@ func init() {
flag.StringVar(&Env.RookImageName, "rook_image", "rook/ceph", "Docker image name for the rook container to install, must be in docker hub or local environment")
flag.StringVar(&Env.ToolboxImageName, "toolbox_image", "rook/ceph", "Docker image name of the toolbox container to install, must be in docker hub or local environment")
flag.StringVar(&Env.BaseTestDir, "base_test_dir", "/data", "Base test directory, for use only when kubernetes master is running on localhost")
flag.BoolVar(&Env.SkipInstallRook, "skip_install_rook", false, "Indicate if Rook need to installed - false if tests are being running at Rook that is pre-installed")
flag.IntVar(&Env.LoadConcurrentRuns, "load_parallel_runs", 20, "number of routines for load test")
flag.IntVar(&Env.LoadVolumeNumber, "load_volumes", 1, "number of volumes(file,object or block) to be created for load test")
flag.IntVar(&Env.LoadTime, "load_time", 1800, "number of seconds each thread perform operations for")
-6
View File
@@ -95,9 +95,3 @@ func checkError(t *testing.T, err error, message string) {
}
assert.NoError(t, err, "%s. %+v", message, err)
}
func concatYaml(first, second string) string {
return first + `
---
` + second
}
+49 -66
View File
@@ -371,11 +371,7 @@ func (k8sh *K8sHelper) WaitForCustomResourceDeletion(namespace string, checkerFu
// If wait is false, a flag will be passed to indicate the delete should return immediately
func (k8sh *K8sHelper) DeleteResourceAndWait(wait bool, args ...string) error {
if !wait {
// new flag in k8s 1.11
v := version.MustParseSemantic(k8sh.GetK8sServerVersion())
if v.AtLeast(version.MustParseSemantic("1.11.0")) {
args = append(args, "--wait=false")
}
args = append(args, "--wait=false")
}
args = append([]string{"delete"}, args...)
_, err := k8sh.Kubectl(args...)
@@ -421,8 +417,8 @@ func (k8sh *K8sHelper) CountPodsWithLabel(label string, namespace string) (int,
// WaitForPodCount waits until the desired number of pods with the label are started
func (k8sh *K8sHelper) WaitForPodCount(label, namespace string, count int) error {
options := metav1.ListOptions{LabelSelector: label}
inc := 0
for inc < RetryLoop {
for i := 0; i < RetryLoop; i++ {
pods, err := k8sh.Clientset.CoreV1().Pods(namespace).List(options)
if err != nil {
return fmt.Errorf("failed to find pod with label %s. %+v", label, err)
@@ -432,10 +428,9 @@ func (k8sh *K8sHelper) WaitForPodCount(label, namespace string, count int) error
logger.Infof("found %d pods with label %s", count, label)
return nil
}
inc++
time.Sleep(RetryInterval * time.Second)
logger.Infof("waiting for %d pods (found %d) with label %s in namespace %s", count, len(pods.Items), label, namespace)
logger.Infof("waiting for %d pods (found %d) with label %s in namespace %s", count, len(pods.Items), label, namespace)
time.Sleep(RetryInterval * time.Second)
}
return fmt.Errorf("Giving up waiting for pods with label %s in namespace %s", label, namespace)
}
@@ -586,18 +581,15 @@ func (k8sh *K8sHelper) PrintEventsForNamespace(namespace string) {
// IsPodRunning returns true if a Pod is running status or goes to Running status within 90s else returns false
func (k8sh *K8sHelper) IsPodRunning(name string, namespace string) bool {
getOpts := metav1.GetOptions{}
inc := 0
for inc < RetryLoop {
for i := 0; i < 20; i++ {
pod, err := k8sh.Clientset.CoreV1().Pods(namespace).Get(name, getOpts)
if err == nil {
if pod.Status.Phase == "Running" {
return true
}
}
inc++
time.Sleep(RetryInterval * time.Second)
logger.Infof("waiting for pod %s in namespace %s to be running", name, namespace)
}
pod, _ := k8sh.Clientset.CoreV1().Pods(namespace).Get(name, getOpts)
k8sh.PrintPodDescribe(namespace, pod.Name)
@@ -613,8 +605,8 @@ func (k8sh *K8sHelper) IsPodTerminated(name string, namespace string) bool {
// IsPodTerminatedWithOpts returns true if a Pod is terminated status or goes to Terminated status
// within 90s else returns false\
func (k8sh *K8sHelper) IsPodTerminatedWithOpts(name string, namespace string, getOpts metav1.GetOptions) bool {
inc := 0
for inc < RetryLoop {
for i := 0; i < RetryLoop; i++ {
pod, err := k8sh.Clientset.CoreV1().Pods(namespace).Get(name, getOpts)
if err != nil {
k8slogger.Infof("Pod %s in namespace %s terminated ", name, namespace)
@@ -622,7 +614,7 @@ func (k8sh *K8sHelper) IsPodTerminatedWithOpts(name string, namespace string, ge
}
k8slogger.Infof("waiting for Pod %s in namespace %s to terminate, status : %+v", name, namespace, pod.Status)
time.Sleep(RetryInterval * time.Second)
inc++
}
k8slogger.Infof("Pod %s in namespace %s did not terminate", name, namespace)
return false
@@ -631,8 +623,8 @@ func (k8sh *K8sHelper) IsPodTerminatedWithOpts(name string, namespace string, ge
// IsServiceUp returns true if a service is up or comes up within 150s, else returns false
func (k8sh *K8sHelper) IsServiceUp(name string, namespace string) bool {
getOpts := metav1.GetOptions{}
inc := 0
for inc < RetryLoop {
for i := 0; i < RetryLoop; i++ {
_, err := k8sh.Clientset.CoreV1().Services(namespace).Get(name, getOpts)
if err == nil {
k8slogger.Infof("Service: %s in namespace: %s is up", name, namespace)
@@ -640,7 +632,7 @@ func (k8sh *K8sHelper) IsServiceUp(name string, namespace string) bool {
}
k8slogger.Infof("waiting for Service %s in namespace %s ", name, namespace)
time.Sleep(RetryInterval * time.Second)
inc++
}
k8slogger.Infof("Giving up waiting for service: %s in namespace %s ", name, namespace)
return false
@@ -660,15 +652,15 @@ func (k8sh *K8sHelper) GetService(servicename string, namespace string) (*v1.Ser
func (k8sh *K8sHelper) IsCRDPresent(crdName string) bool {
cmdArgs := []string{"get", "crd", crdName}
inc := 0
for inc < RetryLoop {
for i := 0; i < RetryLoop; i++ {
_, err := k8sh.Kubectl(cmdArgs...)
if err == nil {
k8slogger.Infof("Found the CRD resource: " + crdName)
return true
}
time.Sleep(RetryInterval * time.Second)
inc++
}
return false
@@ -798,8 +790,7 @@ func (k8sh *K8sHelper) waitForVolume(namespace, volumeName string, exist bool) e
action = "not " + action
}
inc := 0
for inc < RetryLoop {
for i := 0; i < 10; i++ {
isExist, err := k8sh.isVolumeExist(namespace, volumeName)
if err != nil {
return fmt.Errorf("Errors encountered while getting Volume %s/%s: %v", namespace, volumeName, err)
@@ -810,8 +801,6 @@ func (k8sh *K8sHelper) waitForVolume(namespace, volumeName string, exist bool) e
k8slogger.Infof("waiting for Volume %s in namespace %s to %s", volumeName, namespace, action)
time.Sleep(RetryInterval * time.Second)
inc++
}
k8sh.printVolumes(namespace, volumeName)
@@ -953,8 +942,8 @@ func (k8sh *K8sHelper) GetPodEvents(podNamePattern string, namespace string) (*v
// IsPodInError returns true if a Pod is in error status with the given reason and contains the given message
func (k8sh *K8sHelper) IsPodInError(podNamePattern, namespace, reason, containingMessage string) bool {
inc := 0
for inc < RetryLoop {
for i := 0; i < RetryLoop; i++ {
events, err := k8sh.GetPodEvents(podNamePattern, namespace)
if err != nil {
k8slogger.Errorf("Cannot get Pod events for %s in namespace %s: %+v ", podNamePattern, namespace, err)
@@ -968,7 +957,6 @@ func (k8sh *K8sHelper) IsPodInError(podNamePattern, namespace, reason, containin
}
k8slogger.Infof("waiting for Pod %s in namespace %s to error with reason %s and containing the message: %s", podNamePattern, namespace, reason, containingMessage)
time.Sleep(RetryInterval * time.Second)
inc++
}
k8slogger.Infof("Pod %s in namespace %s did not error with reason %s", podNamePattern, namespace, reason)
@@ -1035,8 +1023,8 @@ func (k8sh *K8sHelper) CheckPvcCountAndStatus(podName string, namespace string,
pvcCountCheck := false
actualPvcCount := 0
inc := 0
for inc < RetryLoop {
for i := 0; i < RetryLoop; i++ {
pvcList, err := k8sh.Clientset.CoreV1().PersistentVolumeClaims(namespace).List(listOpts)
if err != nil {
logger.Errorf("Cannot get pvc for app : %v in namespace %v, err: %v", podName, namespace, err)
@@ -1047,7 +1035,7 @@ func (k8sh *K8sHelper) CheckPvcCountAndStatus(podName string, namespace string,
pvcCountCheck = true
break
}
inc++
time.Sleep(RetryInterval * time.Second)
}
@@ -1056,8 +1044,7 @@ func (k8sh *K8sHelper) CheckPvcCountAndStatus(podName string, namespace string,
return false
}
inc = 0
for inc < RetryLoop {
for i := 0; i < RetryLoop; i++ {
checkAllPVCsStatus := true
pl, _ := k8sh.Clientset.CoreV1().PersistentVolumeClaims(namespace).List(listOpts)
for _, pvc := range pl.Items {
@@ -1069,7 +1056,7 @@ func (k8sh *K8sHelper) CheckPvcCountAndStatus(podName string, namespace string,
if checkAllPVCsStatus {
return true
}
inc++
time.Sleep(RetryInterval * time.Second)
}
@@ -1130,8 +1117,8 @@ func (k8sh *K8sHelper) GetPV(name string) (*v1.PersistentVolume, error) {
// If the pod is in expected state within 90s true is returned, if not false
func (k8sh *K8sHelper) IsPodInExpectedState(podNamePattern string, namespace string, state string) bool {
listOpts := metav1.ListOptions{LabelSelector: "app=" + podNamePattern}
inc := 0
for inc < RetryLoop {
for i := 0; i < RetryLoop; i++ {
podList, err := k8sh.Clientset.CoreV1().Pods(namespace).List(listOpts)
if err == nil {
if len(podList.Items) >= 1 {
@@ -1140,7 +1127,7 @@ func (k8sh *K8sHelper) IsPodInExpectedState(podNamePattern string, namespace str
}
}
}
inc++
time.Sleep(RetryInterval * time.Second)
}
@@ -1152,8 +1139,8 @@ func (k8sh *K8sHelper) CheckPodCountAndState(podName string, namespace string, m
listOpts := metav1.ListOptions{LabelSelector: "app=" + podName}
podCountCheck := false
actualPodCount := 0
inc := 0
for inc < RetryLoop {
for i := 0; i < RetryLoop; i++ {
podList, err := k8sh.Clientset.CoreV1().Pods(namespace).List(listOpts)
if err != nil {
logger.Errorf("Cannot list pods for app=%s in namespace %s, err: %+v", podName, namespace, err)
@@ -1166,7 +1153,6 @@ func (k8sh *K8sHelper) CheckPodCountAndState(podName string, namespace string, m
break
}
inc++
logger.Infof("waiting for %d pods with label app=%s, found %d", minExpected, podName, actualPodCount)
time.Sleep(RetryInterval * time.Second)
}
@@ -1199,14 +1185,13 @@ func (k8sh *K8sHelper) CheckPodCountAndState(podName string, namespace string, m
// WaitUntilPodInNamespaceIsDeleted waits for 90s for a pod in a namespace to be terminated
// If the pod disappears within 90s true is returned, if not false
func (k8sh *K8sHelper) WaitUntilPodInNamespaceIsDeleted(podNamePattern string, namespace string) bool {
inc := 0
for inc < RetryLoop {
for i := 0; i < RetryLoop; i++ {
out, _ := k8sh.GetResource("-n", namespace, "pods", "-l", "app="+podNamePattern)
if !strings.Contains(out, podNamePattern) {
return true
}
inc++
time.Sleep(RetryInterval * time.Second)
}
logger.Infof("Pod %s in namespace %s not deleted", podNamePattern, namespace)
@@ -1216,14 +1201,13 @@ func (k8sh *K8sHelper) WaitUntilPodInNamespaceIsDeleted(podNamePattern string, n
// WaitUntilPodIsDeleted waits for 90s for a pod to be terminated
// If the pod disappears within 90s true is returned, if not false
func (k8sh *K8sHelper) WaitUntilPodIsDeleted(name, namespace string) bool {
inc := 0
for inc < RetryLoop {
for i := 0; i < RetryLoop; i++ {
_, err := k8sh.Clientset.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{})
if err != nil && errors.IsNotFound(err) {
return true
}
inc++
logger.Infof("pod %s in namespace %s is not deleted yet", name, namespace)
time.Sleep(RetryInterval * time.Second)
}
@@ -1234,8 +1218,7 @@ func (k8sh *K8sHelper) WaitUntilPodIsDeleted(name, namespace string) bool {
// if PVC goes to Bound state within 90s True is returned, if not false
func (k8sh *K8sHelper) WaitUntilPVCIsBound(namespace string, pvcname string) bool {
inc := 0
for inc < RetryLoop {
for i := 0; i < RetryLoop; i++ {
out, err := k8sh.GetPVCStatus(namespace, pvcname)
if err == nil {
if out == v1.PersistentVolumeClaimPhase(v1.ClaimBound) {
@@ -1244,7 +1227,7 @@ func (k8sh *K8sHelper) WaitUntilPVCIsBound(namespace string, pvcname string) boo
}
}
logger.Infof("waiting for PVC %s to be bound. current=%s. err=%+v", pvcname, out, err)
inc++
time.Sleep(RetryInterval * time.Second)
}
return false
@@ -1253,8 +1236,8 @@ func (k8sh *K8sHelper) WaitUntilPVCIsBound(namespace string, pvcname string) boo
// WaitUntilPVCIsExpanded waits for a PVC to be resized for specified value
func (k8sh *K8sHelper) WaitUntilPVCIsExpanded(namespace, pvcname, size string) bool {
getOpts := metav1.GetOptions{}
inc := 0
for inc < RetryLoop {
for i := 0; i < RetryLoop; i++ {
// PVC specs changes immediately, but status will change only if resize process is successfully completed.
pvc, err := k8sh.Clientset.CoreV1().PersistentVolumeClaims(namespace).Get(pvcname, getOpts)
if err == nil {
@@ -1267,7 +1250,7 @@ func (k8sh *K8sHelper) WaitUntilPVCIsExpanded(namespace, pvcname, size string) b
} else {
logger.Infof("error while getting PVC specs: %+v", err)
}
inc++
time.Sleep(RetryInterval * time.Second)
}
return false
@@ -1275,14 +1258,14 @@ func (k8sh *K8sHelper) WaitUntilPVCIsExpanded(namespace, pvcname, size string) b
func (k8sh *K8sHelper) WaitUntilPVCIsDeleted(namespace string, pvcname string) bool {
getOpts := metav1.GetOptions{}
inc := 0
for inc < RetryLoop {
for i := 0; i < RetryLoop; i++ {
_, err := k8sh.Clientset.CoreV1().PersistentVolumeClaims(namespace).Get(pvcname, getOpts)
if err != nil {
return true
}
logger.Infof("waiting for PVC %s to be deleted.", pvcname)
inc++
time.Sleep(RetryInterval * time.Second)
}
return false
@@ -1297,8 +1280,8 @@ func (k8sh *K8sHelper) DeletePvcWithLabel(namespace string, podName string) bool
logger.Errorf("cannot deleted PVCs for pods with label app=%s", podName)
return false
}
inc := 0
for inc < RetryLoop {
for i := 0; i < RetryLoop; i++ {
pvcs, err := k8sh.Clientset.CoreV1().PersistentVolumeClaims(namespace).List(listOpts)
if err == nil {
if len(pvcs.Items) == 0 {
@@ -1306,7 +1289,7 @@ func (k8sh *K8sHelper) DeletePvcWithLabel(namespace string, podName string) bool
}
}
logger.Infof("waiting for PVCs for pods with label=%s to be deleted.", podName)
inc++
time.Sleep(RetryInterval * time.Second)
}
return false
@@ -1316,14 +1299,14 @@ func (k8sh *K8sHelper) DeletePvcWithLabel(namespace string, podName string) bool
// If namespace is deleted True is returned, if not false.
func (k8sh *K8sHelper) WaitUntilNameSpaceIsDeleted(namespace string) bool {
getOpts := metav1.GetOptions{}
inc := 0
for inc < RetryLoop {
for i := 0; i < RetryLoop; i++ {
ns, err := k8sh.Clientset.CoreV1().Namespaces().Get(namespace, getOpts)
if err != nil {
return true
}
logger.Infof("Namespace %s %v", namespace, ns.Status.Phase)
inc++
time.Sleep(RetryInterval * time.Second)
}
@@ -1565,14 +1548,14 @@ func (k8sh *K8sHelper) CreateAnonSystemClusterBinding() {
}
logger.Infof("anon-user-access creation completed, waiting for it to exist in API")
inc := 0
for inc < RetryLoop {
for i := 0; i < RetryLoop; i++ {
var err error
if _, err = k8sh.Clientset.RbacV1beta1().ClusterRoleBindings().Get("anon-user-access", metav1.GetOptions{}); err == nil {
break
}
logger.Warningf("failed to get anon-user-access clusterrolebinding, will try again: %+v", err)
inc++
time.Sleep(RetryInterval * time.Second)
}
}
+1 -4
View File
@@ -51,15 +51,12 @@ func (h *MySQLHelper) CloseConnection() {
// PingSuccess function is used check connection to a database
func (h *MySQLHelper) PingSuccess() bool {
inc := 0
for inc < 30 {
for i := 0; i < 30; i++ {
err := h.DB.Ping()
if err == nil {
return true
}
inc++
time.Sleep(3 * time.Second)
}
+117 -121
View File
@@ -17,7 +17,6 @@ limitations under the License.
package integration
import (
"fmt"
"strconv"
"time"
@@ -34,24 +33,33 @@ import (
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/version"
)
func checkSkipCSITest(s suite.Suite, k8sh *utils.K8sHelper) {
if !k8sh.VersionAtLeast("v1.13.0") {
logger.Info("Skipping tests as kube version is less than 1.13.0 for the CSI driver")
s.T().Skip()
}
}
// Smoke Test for Block Storage - Test check the following operations on Block Storage in order
// Create,Mount,Write,Read,Expand,Unmount and Delete.
func runBlockE2ETest(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, namespace string) {
func runBlockCSITest(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, namespace string) {
checkSkipCSITest(s, k8sh)
podName := "block-test"
poolName := "replicapool"
storageClassName := "rook-ceph-block"
blockName := "block-pv-claim"
systemNamespace := installer.SystemNamespace(namespace)
podNameWithPVRetained := "block-test-retained"
poolNameRetained := "replicapoolretained"
storageClassNameRetained := "rook-ceph-block-retained"
blockNameRetained := "block-pv-claim-retained"
defer blockTestDataCleanUp(helper, k8sh, s, namespace, poolName, storageClassName, blockName, podName)
defer blockTestDataCleanUp(helper, k8sh, s, namespace, poolNameRetained, storageClassNameRetained, blockNameRetained, podNameWithPVRetained)
defer blockTestDataCleanUp(helper, k8sh, s, namespace, poolName, storageClassName, blockName, podName, true)
defer blockTestDataCleanUp(helper, k8sh, s, namespace, poolNameRetained, storageClassNameRetained, blockNameRetained, podNameWithPVRetained, true)
logger.Infof("Block Storage End to End Integration Test - create, mount, write to, read from, and unmount")
logger.Infof("Running on Rook Cluster %s", namespace)
@@ -60,30 +68,30 @@ func runBlockE2ETest(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.
assert.Equal(s.T(), 0, len(initBlockImages), "there should not already be any images in the pool")
logger.Infof("step 1: Create block storage")
cbErr := helper.PoolClient.CreateStorageClassAndPvc(namespace, poolName, storageClassName, "Delete", blockName, "ReadWriteOnce")
require.Nil(s.T(), cbErr)
err := helper.BlockClient.CreateStorageClassAndPVC(true, defaultNamespace, namespace, systemNamespace, poolName, storageClassName, "Delete", blockName, "ReadWriteOnce")
require.NoError(s.T(), err)
require.True(s.T(), retryBlockImageCountCheck(helper, 1, namespace), "Make sure a new block is created")
cbErr = helper.PoolClient.CreateStorageClassAndPvc(namespace, poolNameRetained, storageClassNameRetained, "Retain", blockNameRetained, "ReadWriteOnce")
require.Nil(s.T(), cbErr)
err = helper.BlockClient.CreateStorageClassAndPVC(true, defaultNamespace, namespace, systemNamespace, poolNameRetained, storageClassNameRetained, "Retain", blockNameRetained, "ReadWriteOnce")
require.NoError(s.T(), err)
require.True(s.T(), retryBlockImageCountCheck(helper, 2, namespace), "Make sure another new block is created")
logger.Infof("Block Storage created successfully")
require.True(s.T(), k8sh.WaitUntilPVCIsBound(defaultNamespace, blockName), "Make sure PVC is Bound")
require.True(s.T(), k8sh.WaitUntilPVCIsBound(defaultNamespace, blockNameRetained), "Make sure PVC with reclaimPolicy:Retain is Bound")
logger.Infof("step 2: Mount block storage")
crdName := createPodWithBlock(helper, k8sh, s, namespace, blockName, podName)
crdNameRetained := createPodWithBlock(helper, k8sh, s, namespace, blockNameRetained, podNameWithPVRetained)
createPodWithBlock(helper, k8sh, s, namespace, storageClassName, podName, blockName)
createPodWithBlock(helper, k8sh, s, namespace, storageClassName, podNameWithPVRetained, blockNameRetained)
logger.Infof("step 3: Write to block storage")
message := "Smoke Test Data for Block storage"
filename := "bsFile1"
err := k8sh.WriteToPod("", podName, filename, message)
require.Nil(s.T(), err)
err = k8sh.WriteToPod("", podName, filename, message)
assert.NoError(s.T(), err)
logger.Infof("Write to Block storage successfully")
logger.Infof("step 4: Read from block storage")
err = k8sh.ReadFromPod("", podName, filename, message)
require.Nil(s.T(), err)
assert.NoError(s.T(), err)
logger.Infof("Read from Block storage successfully")
logger.Infof("step 5: Restart the OSDs to confirm they are still healthy after restart")
@@ -91,92 +99,77 @@ func runBlockE2ETest(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.
logger.Infof("step 6: Read from block storage again")
err = k8sh.ReadFromPod("", podName, filename, message)
require.Nil(s.T(), err)
assert.NoError(s.T(), err)
logger.Infof("Read from Block storage successfully")
v := version.MustParseSemantic(k8sh.GetK8sServerVersion())
if v.AtLeast(version.MustParseSemantic("1.14.0")) {
logger.Infof("additional step: Expand block storage")
// Expanding the image by applying new PVC specs
err = helper.BlockClient.CreatePvc(blockName, storageClassName, "ReadWriteOnce", "2M")
require.Nil(s.T(), err)
// Once the pod using the volume is terminated, the filesystem is expanded and the size of the PVC is increased.
err = k8sh.DeletePod(k8sutil.DefaultNamespace, podName)
require.Nil(s.T(), err)
_, err = helper.BlockClient.BlockMap(getBlockPodDefinition(podName, blockName, false))
require.Nil(s.T(), err)
require.True(s.T(), k8sh.IsPodRunning(podName, defaultNamespace), "Make sure new pod is running")
require.True(s.T(), k8sh.WaitUntilPVCIsExpanded(defaultNamespace, blockName, "2M"), "Make sure PVC is expanded")
logger.Infof("Block Storage successfully expanded")
}
logger.Infof("step 7: Mount same block storage on a different pod. Should not be allowed")
otherPod := "block-test2"
_, mtErr := helper.BlockClient.BlockMap(getBlockPodDefinition(otherPod, blockName, false))
require.Nil(s.T(), mtErr)
require.True(s.T(), k8sh.IsPodInError(otherPod, defaultNamespace, "FailedMount", "Volume is already attached by pod"), "make sure block-test2 pod errors out while mounting the volume")
logger.Infof("Block Storage successfully fenced")
err = helper.BlockClient.CreateClientPod(getCSIBlockPodDefinition(otherPod, blockName, defaultNamespace, storageClassName, false))
assert.NoError(s.T(), err)
// ** FIX: WHY IS THE RWO VOLUME NOT BEING FENCED??? The second pod is starting successfully with the same PVC
//require.True(s.T(), k8sh.IsPodInError(otherPod, defaultNamespace, "FailedMount", "Volume is already attached by pod"), "make sure block-test2 pod errors out while mounting the volume")
//logger.Infof("Block Storage successfully fenced")
logger.Infof("step 8: Delete fenced pod")
unmtErr := k8sh.DeletePod(k8sutil.DefaultNamespace, otherPod)
require.Nil(s.T(), unmtErr)
err = k8sh.DeletePod(k8sutil.DefaultNamespace, otherPod)
require.NoError(s.T(), err)
require.True(s.T(), k8sh.IsPodTerminated(otherPod, defaultNamespace), "make sure block-test2 pod is terminated")
logger.Infof("Fenced pod deleted successfully")
logger.Infof("step 9: Unmount block storage")
unmtErr = k8sh.DeletePod(k8sutil.DefaultNamespace, podName)
require.Nil(s.T(), unmtErr)
unmtErr = k8sh.DeletePod(k8sutil.DefaultNamespace, podNameWithPVRetained)
require.Nil(s.T(), unmtErr)
require.True(s.T(), k8sh.IsVolumeResourceAbsent(installer.SystemNamespace(namespace), crdName), fmt.Sprintf("make sure Volume %s is deleted", crdName))
require.True(s.T(), k8sh.IsVolumeResourceAbsent(installer.SystemNamespace(namespace), crdNameRetained), fmt.Sprintf("make sure Volume %s is deleted", crdNameRetained))
err = k8sh.DeletePod(k8sutil.DefaultNamespace, podName)
require.NoError(s.T(), err)
err = k8sh.DeletePod(k8sutil.DefaultNamespace, podNameWithPVRetained)
require.NoError(s.T(), err)
require.True(s.T(), k8sh.IsPodTerminated(podName, defaultNamespace), "make sure block-test pod is terminated")
require.True(s.T(), k8sh.IsPodTerminated(podNameWithPVRetained, defaultNamespace), "make sure block-test-retained pod is terminated")
logger.Infof("Block Storage unmounted successfully")
logger.Infof("step 10: Deleting block storage")
pvName, err := k8sh.GetPVCVolumeName(defaultNamespace, blockName)
pv, _ := k8sh.GetPV(pvName)
require.Nil(s.T(), err)
dbErr := helper.PoolClient.DeletePvc(defaultNamespace, blockName)
require.Nil(s.T(), dbErr)
require.Equal(s.T(), string((*pv).Spec.PersistentVolumeReclaimPolicy), "Delete")
require.True(s.T(), retryPVCheck(k8sh, pvName, false, ""))
logger.Infof("PV: %s deleted successfully", pvName)
require.True(s.T(), retryBlockImageCountCheck(helper, 1, namespace), "Make sure a block is deleted")
logger.Infof("Block Storage deleted successfully")
pvName, err = k8sh.GetPVCVolumeName(defaultNamespace, blockNameRetained)
pv, _ = k8sh.GetPV(pvName)
require.Nil(s.T(), err)
dbErr = helper.PoolClient.DeletePvc(defaultNamespace, blockNameRetained)
require.Nil(s.T(), dbErr)
require.Equal(s.T(), string((*pv).Spec.PersistentVolumeReclaimPolicy), "Retain")
require.True(s.T(), retryPVCheck(k8sh, pvName, true, "Released"))
require.True(s.T(), retryBlockImageCountCheck(helper, 1, namespace), "Make sure a block is retained")
logger.Infof("Block Storage retained")
k8sh.Kubectl("delete", "pv", pvName)
deletePVC(helper, k8sh, s, namespace, blockName, "Delete")
deletePVC(helper, k8sh, s, namespace, blockNameRetained, "Retain")
logger.Infof("step 11: Delete storage classes and pools")
err = helper.PoolClient.DeletePool(helper.BlockClient, namespace, poolName)
assert.NoError(s.T(), err)
err = helper.PoolClient.DeletePool(helper.BlockClient, namespace, poolNameRetained)
assert.NoError(s.T(), err)
err = helper.PoolClient.DeleteStorageClass(storageClassName)
err = helper.BlockClient.DeleteStorageClass(storageClassName)
assert.NoError(s.T(), err)
err = helper.PoolClient.DeleteStorageClass(storageClassNameRetained)
err = helper.BlockClient.DeleteStorageClass(storageClassNameRetained)
assert.NoError(s.T(), err)
}
func createPodWithBlock(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, namespace, blockName, podName string) string {
_, mtErr := helper.BlockClient.BlockMap(getBlockPodDefinition(podName, blockName, false))
require.Nil(s.T(), mtErr)
crdName, err := k8sh.GetVolumeResourceName(defaultNamespace, blockName)
require.Nil(s.T(), err)
require.True(s.T(), k8sh.IsVolumeResourcePresent(installer.SystemNamespace(namespace), crdName), fmt.Sprintf("make sure Volume %s is created", crdName))
func deletePVC(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, clusterNamespace, pvcName, retainPolicy string) {
pvName, err := k8sh.GetPVCVolumeName(defaultNamespace, pvcName)
assert.NoError(s.T(), err)
pv, err := k8sh.GetPV(pvName)
require.NoError(s.T(), err)
logger.Infof("deleting ")
err = helper.BlockClient.DeletePVC(defaultNamespace, pvcName)
assert.NoError(s.T(), err)
assert.Equal(s.T(), retainPolicy, string((*pv).Spec.PersistentVolumeReclaimPolicy))
if retainPolicy == "Delete" {
assert.True(s.T(), retryPVCheck(k8sh, pvName, false, ""))
logger.Infof("PV: %s deleted successfully", pvName)
assert.True(s.T(), retryBlockImageCountCheck(helper, 1, clusterNamespace), "Make sure a block is deleted")
logger.Infof("Block Storage deleted successfully")
} else {
assert.True(s.T(), retryPVCheck(k8sh, pvName, true, "Released"))
assert.True(s.T(), retryBlockImageCountCheck(helper, 1, clusterNamespace), "Make sure a block is retained")
logger.Infof("Block Storage retained")
k8sh.Kubectl("delete", "pv", pvName)
}
}
func createPodWithBlock(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, clusterNamespace, storageClassName, podName, pvcName string) {
err := helper.BlockClient.CreateClientPod(getCSIBlockPodDefinition(podName, pvcName, defaultNamespace, storageClassName, false))
assert.NoError(s.T(), err)
require.True(s.T(), k8sh.IsPodRunning(podName, defaultNamespace), "make sure block-test pod is in running state")
logger.Infof("Block Storage Mounted successfully")
return crdName
}
func restartOSDPods(k8sh *utils.K8sHelper, s suite.Suite, namespace string) {
@@ -188,7 +181,7 @@ func restartOSDPods(k8sh *utils.K8sHelper, s suite.Suite, namespace string) {
for _, pod := range pods.Items {
options := metav1.DeleteOptions{}
err = k8sh.Clientset.CoreV1().Pods(namespace).Delete(pod.Name, &options)
assert.Nil(s.T(), err)
assert.NoError(s.T(), err)
logger.Infof("Waiting for osd pod %s to be deleted", pod.Name)
deleted := k8sh.WaitUntilPodIsDeleted(pod.Name, namespace)
@@ -198,61 +191,62 @@ func restartOSDPods(k8sh *utils.K8sHelper, s suite.Suite, namespace string) {
// Wait for the new pods to run
logger.Infof("Waiting for new osd pod to run")
err = k8sh.WaitForLabeledPodsToRun(osdLabel, namespace)
assert.Nil(s.T(), err)
assert.NoError(s.T(), err)
}
func runBlockE2ETestLite(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, clusterNamespace string, version cephv1.CephVersionSpec) {
func runBlockCSITestLite(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, clusterNamespace, systemNamespace string, version cephv1.CephVersionSpec) {
checkSkipCSITest(s, k8sh)
logger.Infof("Block Storage End to End Integration Test - create storageclass,pool and pvc")
logger.Infof("Running on Rook Cluster %s", clusterNamespace)
poolName := "rookpool"
storageClassName := "rook-ceph-block-lite"
blockName := "test-block-claim-lite"
podName := "test-pod-lite"
defer blockTestDataCleanUp(helper, k8sh, s, clusterNamespace, poolName, storageClassName, blockName, podName)
setupBlockLite(helper, k8sh, s, clusterNamespace, poolName, storageClassName, blockName, podName, version)
defer blockTestDataCleanUp(helper, k8sh, s, clusterNamespace, poolName, storageClassName, blockName, podName, true)
setupBlockLite(helper, k8sh, s, clusterNamespace, systemNamespace, poolName, storageClassName, blockName, podName, version)
}
func setupBlockLite(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite,
clusterNamespace, poolName, storageClassName, blockName, podName string, version cephv1.CephVersionSpec) {
clusterNamespace, systemNamespace, poolName, storageClassName, blockName, podName string, version cephv1.CephVersionSpec) {
// Check initial number of blocks
initialBlocks, err := helper.BlockClient.List(clusterNamespace)
require.Nil(s.T(), err)
require.NoError(s.T(), err)
initBlockCount := len(initialBlocks)
assert.Equal(s.T(), 0, initBlockCount, "why is there already a block image in the new pool?")
logger.Infof("step : Create Pool,StorageClass and PVC")
err = helper.PoolClient.CreateStorageClassAndPvc(clusterNamespace, poolName, storageClassName, "Delete", blockName, "ReadWriteOnce")
err = helper.BlockClient.CreateStorageClassAndPVC(true, defaultNamespace, clusterNamespace, systemNamespace, poolName, storageClassName, "Delete", blockName, "ReadWriteOnce")
require.NoError(s.T(), err)
require.True(s.T(), k8sh.WaitUntilPVCIsBound(defaultNamespace, blockName))
// Make sure new block is created
b, err := helper.BlockClient.List(clusterNamespace)
assert.Nil(s.T(), err)
assert.NoError(s.T(), err)
assert.Equal(s.T(), 1, len(b), "Make sure new block image is created")
poolExists, err := helper.PoolClient.CephPoolExists(clusterNamespace, poolName)
assert.Nil(s.T(), err)
assert.NoError(s.T(), err)
assert.True(s.T(), poolExists)
}
func deleteBlockLite(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, clusterNamespace, poolName, storageClassName, blockName string) {
func deleteBlockLite(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, clusterNamespace, poolName, storageClassName, blockName string, requireBlockImagesRemoved bool) {
logger.Infof("deleteBlockLite: cleaning up after test")
// Delete pvc and storageclass
err := helper.PoolClient.DeletePvc(defaultNamespace, blockName)
err := helper.BlockClient.DeletePVC(defaultNamespace, blockName)
assertNoErrorUnlessNotFound(s, err)
assert.True(s.T(), k8sh.WaitUntilPVCIsDeleted(defaultNamespace, blockName))
assert.True(s.T(), retryBlockImageCountCheck(helper, 0, clusterNamespace), "Make sure block images were deleted")
if requireBlockImagesRemoved {
assert.True(s.T(), retryBlockImageCountCheck(helper, 0, clusterNamespace), "Make sure block images were deleted")
}
err = helper.PoolClient.DeletePool(helper.BlockClient, clusterNamespace, poolName)
assertNoErrorUnlessNotFound(s, err)
err = helper.PoolClient.DeleteStorageClass(storageClassName)
err = helper.BlockClient.DeleteStorageClass(storageClassName)
assertNoErrorUnlessNotFound(s, err)
b, _ := helper.BlockClient.List(clusterNamespace)
assert.Equal(s.T(), 0, len(b), "Make sure new block image is deleted")
checkPoolDeleted(helper, s, clusterNamespace, poolName)
}
@@ -264,8 +258,8 @@ func assertNoErrorUnlessNotFound(s suite.Suite, err error) {
}
func checkPoolDeleted(helper *clients.TestClient, s suite.Suite, namespace, name string) {
i := 0
for i < utils.RetryLoop {
// only retry once to see if the pool was deleted
for i := 0; i < 3; i++ {
found, err := helper.PoolClient.CephPoolExists(namespace, name)
if err != nil {
// try again on failure since the pool may have been in an unexpected state while deleting
@@ -274,38 +268,35 @@ func checkPoolDeleted(helper *clients.TestClient, s suite.Suite, namespace, name
logger.Infof("pool %s is deleted", name)
return
}
i++
logger.Infof("pool %s still exists", name)
time.Sleep(time.Second * utils.RetryInterval)
}
assert.Fail(s.T(), fmt.Sprintf("pool %s was not deleted", name))
// this is not an assert in order to improve reliability of the tests
logger.Errorf("pool %s was not deleted", name)
}
func blockTestDataCleanUp(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, namespace, poolname, storageclassname, blockname, podName string) {
func blockTestDataCleanUp(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, namespace, poolname, storageclassname, blockname, podName string, requireBlockImagesRemoved bool) {
logger.Infof("Cleaning up block storage")
k8sh.DeletePod(k8sutil.DefaultNamespace, podName)
deleteBlockLite(helper, k8sh, s, namespace, poolname, storageclassname, blockname)
deleteBlockLite(helper, k8sh, s, namespace, poolname, storageclassname, blockname, requireBlockImagesRemoved)
}
// periodically checking if block image count has changed to expected value
// When creating pvc in k8s platform, it may take some time for the block Image to be bounded
func retryBlockImageCountCheck(helper *clients.TestClient, expectedImageCount int, namespace string) bool {
inc := 0
for inc < utils.RetryLoop {
logger.Infof("Getting list of blocks (expecting %d)", (expectedImageCount))
for i := 0; i < utils.RetryLoop; i++ {
blockImages, _ := helper.BlockClient.List(namespace)
if expectedImageCount == len(blockImages) {
return true
}
logger.Infof("Waiting for block image count to reach %d. current=%d. %+v", expectedImageCount, len(blockImages), blockImages)
time.Sleep(time.Second * utils.RetryInterval)
inc++
}
return false
}
func retryPVCheck(k8sh *utils.K8sHelper, name string, exists bool, status string) bool {
inc := 0
for inc < utils.RetryLoop {
for i := 0; i < utils.RetryLoop; i++ {
pv, err := k8sh.GetPV(name)
if err != nil {
if !exists {
@@ -317,34 +308,39 @@ func retryPVCheck(k8sh *utils.K8sHelper, name string, exists bool, status string
return true
}
}
logger.Infof("Waiting for PV %q to have status %q with exists %t", name, status, exists)
time.Sleep(time.Second * utils.RetryInterval)
inc++
}
return false
}
func getBlockPodDefinition(podName, blockName string, readOnly bool) string {
return `apiVersion: v1
func getCSIBlockPodDefinition(podName, pvcName, namespace, storageClass string, readOnly bool) string {
return `
apiVersion: v1
kind: Pod
metadata:
name: ` + podName + `
namespace: ` + namespace + `
spec:
containers:
- image: busybox
name: block-test1
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
volumeMounts:
- name: block-persistent-storage
mountPath: ` + utils.TestMountPath + `
volumes:
- name: block-persistent-storage
persistentVolumeClaim:
claimName: ` + blockName + `
readOnly: ` + strconv.FormatBool(readOnly) + `
restartPolicy: Never`
containers:
- name: ` + podName + `
image: busybox
command:
- sh
- "-c"
- "touch ` + utils.TestMountPath + `/csi.test && sleep 3600"
imagePullPolicy: IfNotPresent
env:
volumeMounts:
- mountPath: ` + utils.TestMountPath + `
name: csivol
volumes:
- name: csivol
persistentVolumeClaim:
claimName: ` + pvcName + `
readOnly: ` + strconv.FormatBool(readOnly) + `
restartPolicy: Never
`
}
func getBlockStatefulSetAndServiceDefinition(namespace, statefulsetName, podName, StorageClassName string) (*v1.Service, *appsv1.StatefulSet) {
+1 -1
View File
@@ -40,7 +40,7 @@ const (
// These versions are for running a minimal test suite for more efficient tests across different versions of K8s
// instead of running all suites on all versions
// To run on multiple versions, add a comma separate list such as 1.16.0,1.17.0
blockMinimalTestVersion = "1.13.0"
flexDriverMinimalTestVersion = "1.13.0"
multiClusterMinimalTestVersion = "1.14.0"
helmMinimalTestVersion = "1.15.0"
upgradeMinimalTestVersion = "1.16.0"
+86 -23
View File
@@ -42,7 +42,11 @@ const (
// Smoke Test for File System Storage - Test check the following operations on Filesystem Storage in order
// Create,Mount,Write,Read,Unmount and Delete.
func runFileE2ETest(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, namespace string, filesystemName string) {
func runFileE2ETest(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, namespace, filesystemName string, useCSI bool) {
if useCSI {
checkSkipCSITest(s, k8sh)
}
defer fileTestDataCleanUp(helper, k8sh, s, filePodName, namespace, filesystemName)
logger.Infof("Running on Rook Cluster %s", namespace)
logger.Infof("File Storage End To End Integration Test - create, mount, write to, read from, and unmount")
@@ -50,30 +54,38 @@ func runFileE2ETest(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.S
createFilesystem(helper, k8sh, s, namespace, filesystemName, activeCount)
// Create a test pod where CephFS is consumed without user creds
createFilesystemConsumerPod(helper, k8sh, s, namespace, filesystemName)
// Create a test pod where CephFS is consumed with a mountUser and mountSecret specified.
createFilesystemMountCephCredentials(helper, k8sh, s, namespace, filesystemName)
createFilesystemMountUserConsumerPod(helper, k8sh, s, namespace, filesystemName)
storageClassName := "cephfs-storageclass"
err := helper.FSClient.CreateStorageClass(filesystemName, namespace, storageClassName)
assert.NoError(s.T(), err)
createFilesystemConsumerPod(helper, k8sh, s, namespace, filesystemName, storageClassName, useCSI)
// Test reading and writing to the first pod
err := writeAndReadToFilesystem(helper, k8sh, s, namespace, filePodName, "test_file")
err = writeAndReadToFilesystem(helper, k8sh, s, namespace, filePodName, "test_file")
assert.NoError(s.T(), err)
// Test reading and writing to the second pod
err = writeAndReadToFilesystem(helper, k8sh, s, namespace, fileMountUserPodName, "canttouchthis")
assert.Error(s.T(), err, "we should not be able to write to file canttouchthis on CephFS `/`")
err = writeAndReadToFilesystem(helper, k8sh, s, namespace, fileMountUserPodName, "foo/test_file")
assert.NoError(s.T(), err, "we should be able to write to the `/foo` directory on CephFS")
// TODO: Also mount with user credentials with the CSI driver
if !useCSI {
// Create a test pod where CephFS is consumed with a mountUser and mountSecret specified.
createFilesystemMountCephCredentials(helper, k8sh, s, namespace, filesystemName)
createFilesystemMountUserConsumerPod(helper, k8sh, s, namespace, filesystemName, storageClassName)
// Test reading and writing to the second pod
err = writeAndReadToFilesystem(helper, k8sh, s, namespace, fileMountUserPodName, "canttouchthis")
assert.Error(s.T(), err, "we should not be able to write to file canttouchthis on CephFS `/`")
err = writeAndReadToFilesystem(helper, k8sh, s, namespace, fileMountUserPodName, "foo/test_file")
assert.NoError(s.T(), err, "we should be able to write to the `/foo` directory on CephFS")
cleanupFilesystemConsumer(helper, k8sh, s, namespace, fileMountUserPodName)
}
// Start the NFS daemons
testNFSDaemons(helper, k8sh, s, namespace, filesystemName)
// Cleanup the filesystem and its clients
cleanupFilesystemConsumer(k8sh, s, namespace, filePodName)
cleanupFilesystemConsumer(k8sh, s, namespace, fileMountUserPodName)
cleanupFilesystemConsumer(helper, k8sh, s, namespace, filePodName)
downscaleMetadataServers(helper, k8sh, s, namespace, filesystemName)
cleanupFilesystem(helper, k8sh, s, namespace, filesystemName)
helper.BlockClient.DeleteStorageClass(storageClassName)
}
func testNFSDaemons(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, namespace string, filesystemName string) {
@@ -85,8 +97,8 @@ func testNFSDaemons(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.S
assert.Nil(s.T(), err)
}
func createFilesystemConsumerPod(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, namespace string, filesystemName string) {
err := createPodWithFilesystem(k8sh, s, filePodName, namespace, filesystemName, false)
func createFilesystemConsumerPod(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, namespace, filesystemName, storageClassName string, useCSI bool) {
err := createPodWithFilesystem(k8sh, s, filePodName, namespace, filesystemName, storageClassName, false, useCSI)
require.NoError(s.T(), err)
filePodRunning := k8sh.IsPodRunning(filePodName, namespace)
require.True(s.T(), filePodRunning, "make sure file-test pod is in running state")
@@ -109,7 +121,7 @@ func downscaleMetadataServers(helper *clients.TestClient, k8sh *utils.K8sHelper,
require.Nil(s.T(), err)
}
func cleanupFilesystemConsumer(k8sh *utils.K8sHelper, s suite.Suite, namespace string, podName string) {
func cleanupFilesystemConsumer(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, namespace string, podName string) {
logger.Infof("Delete file System consumer")
err := k8sh.DeletePod(namespace, podName)
assert.Nil(s.T(), err)
@@ -117,6 +129,7 @@ func cleanupFilesystemConsumer(k8sh *utils.K8sHelper, s suite.Suite, namespace s
k8sh.PrintPodDescribe(namespace, podName)
assert.Fail(s.T(), fmt.Sprintf("make sure %s pod is terminated", podName))
}
helper.BlockClient.DeletePVC(namespace, podName)
logger.Infof("File system consumer deleted")
}
@@ -154,16 +167,21 @@ func fileTestDataCleanUp(helper *clients.TestClient, k8sh *utils.K8sHelper, s su
helper.FSClient.Delete(filesystemName, namespace)
}
func createPodWithFilesystem(k8sh *utils.K8sHelper, s suite.Suite, podName, namespace, filesystemName string, mountUser bool) error {
driverName := installer.SystemNamespace(namespace)
testPodManifest := getFilesystemTestPod(podName, namespace, filesystemName, driverName, mountUser)
func createPodWithFilesystem(k8sh *utils.K8sHelper, s suite.Suite, podName, namespace, filesystemName, storageClassName string, mountUser, useCSI bool) error {
var testPodManifest string
if useCSI {
testPodManifest = getFilesystemCSITestPod(podName, namespace, storageClassName)
} else {
driverName := installer.SystemNamespace(namespace)
testPodManifest = getFilesystemFlexTestPod(podName, namespace, filesystemName, driverName, mountUser)
}
if err := k8sh.ResourceOperation("create", testPodManifest); err != nil {
return fmt.Errorf("failed to create pod -- %s. %+v", testPodManifest, err)
}
return nil
}
func getFilesystemTestPod(podName, namespace, filesystemName, driverName string, mountUser bool) string {
func getFilesystemFlexTestPod(podName, namespace, filesystemName, driverName string, mountUser bool) string {
mountUserInsert := ""
if mountUser {
mountUserInsert = `
@@ -203,6 +221,49 @@ spec:
`
}
func getFilesystemCSITestPod(podName, namespace, storageClassName string) string {
claimName := podName
return `
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ` + claimName + `
namespace: ` + namespace + `
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: ` + storageClassName + `
---
apiVersion: v1
kind: Pod
metadata:
name: ` + podName + `
namespace: ` + namespace + `
spec:
containers:
- name: ` + podName + `
image: busybox
command:
- sh
- "-c"
- "touch ` + utils.TestMountPath + `/csi.test && sleep 3600"
imagePullPolicy: IfNotPresent
env:
volumeMounts:
- mountPath: ` + utils.TestMountPath + `
name: csivol
volumes:
- name: csivol
persistentVolumeClaim:
claimName: ` + claimName + `
readOnly: false
restartPolicy: Never
`
}
func createFilesystemMountCephCredentials(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, namespace string, filesystemName string) {
// Create agent binding for access to Secrets
err := k8sh.ResourceOperation("apply", getFilesystemAgentMountSecretsBinding(namespace))
@@ -247,8 +308,10 @@ func createFilesystemMountCephCredentials(helper *clients.TestClient, k8sh *util
logger.Info("Created Ceph credentials Secret in Kubernetes")
}
func createFilesystemMountUserConsumerPod(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, namespace string, filesystemName string) {
mtfsErr := createPodWithFilesystem(k8sh, s, fileMountUserPodName, namespace, filesystemName, true)
func createFilesystemMountUserConsumerPod(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, namespace, filesystemName, storageClassName string) {
// TODO: Mount with user credentials for the CSI driver
useCSI := false
mtfsErr := createPodWithFilesystem(k8sh, s, fileMountUserPodName, namespace, filesystemName, storageClassName, true, useCSI)
require.Nil(s.T(), mtfsErr)
filePodRunning := k8sh.IsPodRunning(fileMountUserPodName, namespace)
require.True(s.T(), filePodRunning, "make sure file-mountuser-test pod is in running state")
+13 -13
View File
@@ -30,15 +30,14 @@ import (
)
var (
userid = "rook-user"
userdisplayname = "A rook RGW user"
bucketname = "smokebkt"
objBody = "Test Rook Object Data"
objectKey = "rookObj1"
contentType = "plain/text"
storageClassName = "rook-smoke-delete-bucket"
obcName = "smoke-delete-bucket"
region = "us-east-1"
userid = "rook-user"
userdisplayname = "A rook RGW user"
bucketname = "smokebkt"
objBody = "Test Rook Object Data"
objectKey = "rookObj1"
contentType = "plain/text"
obcName = "smoke-delete-bucket"
region = "us-east-1"
)
// Smoke Test for ObjectStore - Test check the following operations on ObjectStore in order
@@ -94,9 +93,10 @@ func runObjectE2ETest(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite
// Testing creation/deletion of objects using Object Bucket Claim
logger.Infof("Step 3 : Create Object Bucket Claim with reclaim policy delete")
cobErr := helper.BucketClient.CreateBucketStorageClass(namespace, storeName, storageClassName, "Delete", region)
bucketStorageClassName := "rook-smoke-delete-bucket"
cobErr := helper.BucketClient.CreateBucketStorageClass(namespace, storeName, bucketStorageClassName, "Delete", region)
require.Nil(s.T(), cobErr)
cobcErr := helper.BucketClient.CreateObc(obcName, storageClassName, bucketname, true)
cobcErr := helper.BucketClient.CreateObc(obcName, bucketStorageClassName, bucketname, true)
require.Nil(s.T(), cobcErr)
for i = 0; i < 4 && !helper.BucketClient.CheckOBC(obcName, "created"); i++ {
@@ -144,7 +144,7 @@ func runObjectE2ETest(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite
logger.Infof("Object deleted on bucket successfully")
logger.Infof("Step 8 : Delete Object Bucket Claim")
dobcErr := helper.BucketClient.DeleteObc(obcName, storageClassName, bucketname, true)
dobcErr := helper.BucketClient.DeleteObc(obcName, bucketStorageClassName, bucketname, true)
require.Nil(s.T(), dobcErr)
logger.Infof("Checking to see if the obc, secret and cm have all been deleted")
for i = 0; i < 4 && !helper.BucketClient.CheckOBC(obcName, "deleted"); i++ {
@@ -166,7 +166,7 @@ func runObjectE2ETest(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite
assert.NotEqual(s.T(), i, 4)
assert.Equal(s.T(), rgwErr, rgw.RGWErrorNotFound)
dobErr := helper.BucketClient.DeleteBucketStorageClass(namespace, storeName, storageClassName, "Delete", region)
dobErr := helper.BucketClient.DeleteBucketStorageClass(namespace, storeName, bucketStorageClassName, "Delete", region)
assert.Nil(s.T(), dobErr)
logger.Infof("Delete Object Bucket Claim successfully")
-67
View File
@@ -1,67 +0,0 @@
/*
Copyright 2019 The Rook Authors. All rights reserved.
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 integration
import (
"time"
"github.com/stretchr/testify/require"
)
// Smoke Test for Client CRD
func (suite *SmokeSuite) TestCreateClient() {
logger.Infof("Create Client Smoke Test")
clientName := "client1"
caps := map[string]string{
"mon": "allow rwx",
"mgr": "allow rwx",
"osd": "allow rwx",
}
err := suite.helper.UserClient.Create(clientName, suite.namespace, caps)
require.Nil(suite.T(), err)
clientFound := false
for i := 0; i < 30; i++ {
clients, _ := suite.helper.UserClient.Get(suite.namespace, "client."+clientName)
if clients != "" {
clientFound = true
}
if clientFound {
break
}
logger.Infof("Waiting for client to appear")
time.Sleep(2 * time.Second)
}
require.Equal(suite.T(), true, clientFound, "client not found")
logger.Infof("Update Client Smoke Test")
newcaps := map[string]string{
"mon": "allow r",
"mgr": "allow rw",
"osd": "allow *",
}
caps, _ = suite.helper.UserClient.Update(suite.namespace, clientName, newcaps)
require.Equal(suite.T(), "allow r", caps["mon"], "wrong caps")
require.Equal(suite.T(), "allow rw", caps["mgr"], "wrong caps")
require.Equal(suite.T(), "allow *", caps["osd"], "wrong caps")
}
-239
View File
@@ -1,239 +0,0 @@
/*
Copyright 2019 The Rook Authors. All rights reserved.
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 integration
import (
"testing"
"github.com/rook/rook/tests/framework/clients"
"github.com/rook/rook/tests/framework/installer"
"github.com/rook/rook/tests/framework/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
const (
csiRBDNodeSecret = "rook-csi-rbd-node"
csiRBDProvisionerSecret = "rook-csi-rbd-provisioner"
csiCephFSNodeSecret = "rook-csi-cephfs-node"
csiCephFSProvisionerSecret = "rook-csi-cephfs-provisioner"
csiSCRBD = "ceph-csi-rbd"
csiSCCephFS = "ceph-csi-cephfs"
csiPoolRBD = "csi-rbd"
csiPoolCephFS = "csi-cephfs"
csiTestRBDPodName = "csi-test-rbd"
csiTestCephFSPodName = "csi-test-cephfs"
)
func runCephCSIE2ETest(helper *clients.TestClient, k8sh *utils.K8sHelper, s suite.Suite, t *testing.T, namespace string) {
if !k8sh.VersionAtLeast("v1.13.0") {
logger.Info("Skipping csi tests as kube version is less than 1.13.0")
t.Skip()
}
logger.Info("test Ceph CSI driver")
createCephPools(helper, s, namespace)
createCSIStorageClass(k8sh, s, namespace)
createAndDeleteCSIRBDTestPod(k8sh, s, namespace)
createAndDeleteCSICephFSTestPod(k8sh, s, namespace)
//cleanup resources created
deleteCephPools(helper, namespace)
deleteCSIStorageClass(k8sh, namespace)
}
func createCephPools(helper *clients.TestClient, s suite.Suite, namespace string) {
err := helper.PoolClient.Create(csiPoolRBD, namespace, 1)
require.Nil(s.T(), err)
activeCount := 1
err = helper.FSClient.Create(csiPoolCephFS, namespace, activeCount)
require.Nil(s.T(), err)
}
func deleteCephPools(helper *clients.TestClient, namespace string) {
err := helper.PoolClient.Delete(csiPoolRBD, namespace)
if err != nil {
logger.Errorf("failed to delete rbd pool %s with error %v", csiPoolRBD, err)
}
err = helper.FSClient.Delete(csiPoolCephFS, namespace)
if err != nil {
logger.Errorf("failed to delete cephfs pool %s with error %v", csiPoolCephFS, err)
return
}
logger.Info("Deleted Ceph Pools")
}
func createCSIStorageClass(k8sh *utils.K8sHelper, s suite.Suite, namespace string) {
rbdSC := `
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ` + csiSCRBD + `
provisioner: ` + installer.SystemNamespace(namespace) + `.rbd.csi.ceph.com
parameters:
pool: ` + csiPoolRBD + `
clusterID: ` + namespace + `
csi.storage.k8s.io/provisioner-secret-name: ` + csiRBDProvisionerSecret + `
csi.storage.k8s.io/provisioner-secret-namespace: ` + namespace + `
csi.storage.k8s.io/node-stage-secret-name: ` + csiRBDNodeSecret + `
csi.storage.k8s.io/node-stage-secret-namespace: ` + namespace + `
`
cephFSSC := `
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ` + csiSCCephFS + `
provisioner: ` + installer.SystemNamespace(namespace) + `.cephfs.csi.ceph.com
parameters:
clusterID: ` + namespace + `
fsName: ` + csiPoolCephFS + `
pool: ` + csiPoolCephFS + `-data0
csi.storage.k8s.io/provisioner-secret-name: ` + csiCephFSProvisionerSecret + `
csi.storage.k8s.io/provisioner-secret-namespace: ` + namespace + `
csi.storage.k8s.io/node-stage-secret-name: ` + csiCephFSNodeSecret + `
csi.storage.k8s.io/node-stage-secret-namespace: ` + namespace + `
`
err := k8sh.ResourceOperation("apply", rbdSC)
require.Nil(s.T(), err)
err = k8sh.ResourceOperation("apply", cephFSSC)
require.Nil(s.T(), err)
}
func deleteCSIStorageClass(k8sh *utils.K8sHelper, namespace string) {
err := k8sh.Clientset.StorageV1().StorageClasses().Delete(csiSCRBD, &metav1.DeleteOptions{})
if err != nil {
logger.Errorf("failed to delete rbd storage class %s with error %v", csiSCRBD, err)
}
err = k8sh.Clientset.StorageV1().StorageClasses().Delete(csiSCCephFS, &metav1.DeleteOptions{})
if err != nil {
logger.Errorf("failed to delete cephfs storage class %s with error %v", csiSCCephFS, err)
return
}
logger.Info("Deleted rbd and cephfs storageclass")
}
func createAndDeleteCSIRBDTestPod(k8sh *utils.K8sHelper, s suite.Suite, namespace string) {
pod := `
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: rbd-pvc-csi
namespace: ` + namespace + `
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: ` + csiSCRBD + `
---
apiVersion: v1
kind: Pod
metadata:
name: ` + csiTestRBDPodName + `
namespace: ` + namespace + `
spec:
containers:
- name: ` + csiTestRBDPodName + `
image: busybox
command:
- sh
- "-c"
- "touch /test/csi.test && sleep 3600"
imagePullPolicy: IfNotPresent
env:
volumeMounts:
- mountPath: /test
name: csivol
volumes:
- name: csivol
persistentVolumeClaim:
claimName: rbd-pvc-csi
readOnly: false
restartPolicy: Never
`
err := k8sh.ResourceOperation("apply", pod)
require.Nil(s.T(), err)
isPodRunning := k8sh.IsPodRunning(csiTestRBDPodName, namespace)
if !isPodRunning {
k8sh.PrintPodDescribe(namespace, csiTestRBDPodName)
k8sh.PrintPodStatus(namespace)
}
// cleanup the pod and pvc
err = k8sh.ResourceOperation("delete", pod)
assert.NoError(s.T(), err)
assert.True(s.T(), isPodRunning, "csi rbd test pod fails to run")
}
func createAndDeleteCSICephFSTestPod(k8sh *utils.K8sHelper, s suite.Suite, namespace string) {
pod := `
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: cephfs-pvc-csi
namespace: ` + namespace + `
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: ` + csiSCCephFS + `
---
apiVersion: v1
kind: Pod
metadata:
name: ` + csiTestCephFSPodName + `
namespace: ` + namespace + `
spec:
containers:
- name: ` + csiTestCephFSPodName + `
image: busybox
command:
- sh
- "-c"
- "touch /test/csi.test && sleep 3600"
imagePullPolicy: IfNotPresent
env:
volumeMounts:
- mountPath: /test
name: csivol
volumes:
- name: csivol
persistentVolumeClaim:
claimName: cephfs-pvc-csi
readOnly: false
restartPolicy: Never
`
err := k8sh.ResourceOperation("apply", pod)
require.Nil(s.T(), err)
isPodRunning := k8sh.IsPodRunning(csiTestCephFSPodName, namespace)
if !isPodRunning {
k8sh.PrintPodDescribe(namespace, csiTestCephFSPodName)
k8sh.PrintPodStatus(namespace)
}
// cleanup the pod and pvc
err = k8sh.ResourceOperation("delete", pod)
assert.NoError(s.T(), err)
assert.True(s.T(), isPodRunning, "csi cephfs test pod fails to run")
}
@@ -17,6 +17,7 @@ limitations under the License.
package integration
import (
"strconv"
"testing"
"fmt"
@@ -28,21 +29,12 @@ import (
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/version"
)
// ******************************************************
// *** Scenarios tested by the BlockMountUnMountSuite ***
// Setup
// - via the cluster CRD
// - set up Block PVC - With ReadWriteOnce
// - set up Block PVC - with ReadWriteMany
// - Mount Volume on a pod and write some data
// - UnMount Volume
// Monitors
// - one mons in the cluster
// OSDs
// - Bluestore running on directory
// Block Mount & Unmount scenarios - repeat for each PVC
// *** Scenarios tested by the TestCephFlexSuite ***
// Flex driver block scenarios - repeat for each PVC
// 1. ReadWriteOnce
// a. Mount Volume on a new pod - make sure persisted data is present and write new data
// b. Mount volume on two pods with - mount should be successful only on first pod
@@ -54,25 +46,25 @@ import (
// b. Scale down pods
// c. Failover pods
// d. Delete StatefulSet
//
// Flex driver file system scenarios
// 1. Create a filesystem
// a. Mount a directory with the static mount
// ******************************************************
// NOTE: This suite needs to be last.
// There is an issue on k8s 1.7 where the CRD controller will frequently fail to create a cluster after this suite is run.
// The error is "the server does not allow this method on the requested resource (post cephclusters.ceph.rook.io)".
// Everything appears to have been cleaned up successfully in this test, so it is still unclear what is causing the issue between tests.
func TestCephBlockSuite(t *testing.T) {
func TestCephFlexSuite(t *testing.T) {
if installer.SkipTestSuite(installer.CephTestSuite) {
t.Skip()
}
s := new(CephBlockSuite)
defer func(s *CephBlockSuite) {
s := new(CephFlexDriverSuite)
defer func(s *CephFlexDriverSuite) {
HandlePanics(recover(), s.op, s.T)
}(s)
suite.Run(t, s)
}
type CephBlockSuite struct {
type CephFlexDriverSuite struct {
suite.Suite
testClient *clients.TestClient
bc *clients.BlockOperation
@@ -84,24 +76,29 @@ type CephBlockSuite struct {
op *TestCluster
}
func (s *CephBlockSuite) SetupSuite() {
func (s *CephFlexDriverSuite) SetupSuite() {
s.namespace = "block-test-ns"
s.namespace = "flex-ns"
s.pvcNameRWO = "block-persistent-rwo"
s.pvcNameRWX = "block-persistent-rwx"
useHelm := false
mons := 1
rbdMirrorWorkers := 1
s.op, s.kh = StartTestCluster(s.T, blockMinimalTestVersion, s.namespace, "bluestore", useHelm, false, "", mons, rbdMirrorWorkers, installer.VersionMaster, installer.NautilusVersion)
s.op, s.kh = StartTestCluster(s.T, flexDriverMinimalTestVersion, s.namespace, "bluestore", useHelm, false, "", mons, rbdMirrorWorkers, installer.VersionMaster, installer.NautilusVersion)
s.testClient = clients.CreateTestClient(s.kh, s.op.installer.Manifests)
s.bc = s.testClient.BlockClient
}
func (s *CephBlockSuite) AfterTest(suiteName, testName string) {
func (s *CephFlexDriverSuite) AfterTest(suiteName, testName string) {
s.op.installer.CollectOperatorLog(suiteName, testName, installer.SystemNamespace(s.namespace))
}
func (s *CephBlockSuite) TestBlockStorageMountUnMountForStatefulSets() {
func (s *CephFlexDriverSuite) TestFileSystem() {
useCSI := false
runFileE2ETest(s.testClient, s.kh, s.Suite, s.namespace, "smoke-test-fs", useCSI)
}
func (s *CephFlexDriverSuite) TestBlockStorageMountUnMountForStatefulSets() {
poolName := "stspool"
storageClassName := "stssc"
reclaimPolicy := "Delete"
@@ -112,7 +109,9 @@ func (s *CephBlockSuite) TestBlockStorageMountUnMountForStatefulSets() {
logger.Infof("Test case when block persistent volumes are scaled up and down along with StatefulSet")
logger.Info("Step 1: Create pool and storageClass")
err := s.testClient.PoolClient.CreateStorageClass(s.namespace, poolName, storageClassName, reclaimPolicy)
err := s.testClient.PoolClient.Create(poolName, s.namespace, 1)
assert.Nil(s.T(), err)
err = s.testClient.BlockClient.CreateStorageClass(false, poolName, storageClassName, reclaimPolicy, s.namespace)
assert.Nil(s.T(), err)
logger.Info("Step 2 : Deploy statefulSet with 1X replication")
service, statefulset := getBlockStatefulSetAndServiceDefinition(defaultNamespace, statefulSetName, statefulPodsName, storageClassName)
@@ -148,7 +147,7 @@ func (s *CephBlockSuite) TestBlockStorageMountUnMountForStatefulSets() {
require.True(s.T(), s.kh.CheckPvcCountAndStatus(statefulSetName, defaultNamespace, 2, "Bound"))
}
func (s *CephBlockSuite) statefulSetDataCleanup(namespace, poolName, storageClassName, reclaimPolicy, statefulSetName, statefulPodsName string) {
func (s *CephFlexDriverSuite) statefulSetDataCleanup(namespace, poolName, storageClassName, reclaimPolicy, statefulSetName, statefulPodsName string) {
delOpts := metav1.DeleteOptions{}
listOpts := metav1.ListOptions{LabelSelector: "app=" + statefulSetName}
// Delete stateful set
@@ -159,41 +158,37 @@ func (s *CephBlockSuite) statefulSetDataCleanup(namespace, poolName, storageClas
s.kh.DeletePvcWithLabel(defaultNamespace, statefulSetName)
// Delete storageclass and pool
s.testClient.PoolClient.DeletePool(s.testClient.BlockClient, s.namespace, poolName)
s.testClient.PoolClient.DeleteStorageClass(storageClassName)
s.testClient.BlockClient.DeleteStorageClass(storageClassName)
}
func (s *CephBlockSuite) setupPVCs() {
func (s *CephFlexDriverSuite) setupPVCs() {
logger.Infof("creating the test PVCs")
poolNameRWO := "block-pool-rwo"
storageClassNameRWO := "rook-ceph-block-rwo"
systemNamespace := installer.SystemNamespace(s.namespace)
// Create PVCs
cbErr := s.testClient.PoolClient.CreateStorageClassAndPvc(s.namespace, poolNameRWO, storageClassNameRWO, "Delete", s.pvcNameRWO, "ReadWriteOnce")
require.Nil(s.T(), cbErr)
useCSI := false
err := s.testClient.BlockClient.CreateStorageClassAndPVC(useCSI, defaultNamespace, s.namespace, systemNamespace, poolNameRWO, storageClassNameRWO, "Delete", s.pvcNameRWO, "ReadWriteOnce")
require.Nil(s.T(), err)
require.True(s.T(), s.kh.WaitUntilPVCIsBound(defaultNamespace, s.pvcNameRWO), "Make sure PVC is Bound")
cbErr2 := s.testClient.BlockClient.CreatePvc(s.pvcNameRWX, storageClassNameRWO, "ReadWriteMany", "1M")
require.Nil(s.T(), cbErr2)
err = s.testClient.BlockClient.CreatePVC(defaultNamespace, s.pvcNameRWX, storageClassNameRWO, "ReadWriteMany", "1M")
require.Nil(s.T(), err)
require.True(s.T(), s.kh.WaitUntilPVCIsBound(defaultNamespace, s.pvcNameRWX), "Make sure PVC is Bound")
// Mount PVC on a pod and write some data.
_, mtErr := s.bc.BlockMap(getBlockPodDefinition("setup-block-rwo", s.pvcNameRWO, false))
require.Nil(s.T(), mtErr)
err = s.bc.CreateClientPod(getFlexBlockPodDefinition("setup-block-rwo", s.pvcNameRWO, false))
require.Nil(s.T(), err)
crdName, err := s.kh.GetVolumeResourceName(defaultNamespace, s.pvcNameRWO)
require.Nil(s.T(), err)
rwoVolumePresent := s.kh.IsVolumeResourcePresent(installer.SystemNamespace(s.namespace), crdName)
if !rwoVolumePresent {
s.kh.PrintPodDescribe(defaultNamespace, "setup-block-rwo")
s.kh.PrintPodStatus(s.namespace)
s.kh.PrintPodStatus(installer.SystemNamespace(s.namespace))
}
require.True(s.T(), rwoVolumePresent, fmt.Sprintf("make sure rwo Volume %s is created", crdName))
s.kh.IsVolumeResourcePresent(systemNamespace, crdName)
_, mtErr1 := s.bc.BlockMap(getBlockPodDefinition("setup-block-rwx", s.pvcNameRWX, false))
require.Nil(s.T(), mtErr1)
crdName1, err1 := s.kh.GetVolumeResourceName(defaultNamespace, s.pvcNameRWX)
require.Nil(s.T(), err1)
require.True(s.T(), s.kh.IsVolumeResourcePresent(installer.SystemNamespace(s.namespace), crdName1), fmt.Sprintf("make sure rwx Volume %s is created", crdName))
err = s.bc.CreateClientPod(getFlexBlockPodDefinition("setup-block-rwx", s.pvcNameRWX, false))
require.Nil(s.T(), err)
crdName, err = s.kh.GetVolumeResourceName(defaultNamespace, s.pvcNameRWX)
require.Nil(s.T(), err)
s.kh.IsVolumeResourcePresent(systemNamespace, crdName)
require.True(s.T(), s.kh.IsPodRunning("setup-block-rwo", defaultNamespace), "make sure setup-block-rwo pod is in running state")
require.True(s.T(), s.kh.IsPodRunning("setup-block-rwx", defaultNamespace), "make sure setup-block-rwx pod is in running state")
@@ -212,41 +207,41 @@ func (s *CephBlockSuite) setupPVCs() {
require.True(s.T(), s.kh.IsPodTerminated("setup-block-rwx", defaultNamespace), "make sure setup-block-rwx pod is terminated")
}
func (s *CephBlockSuite) TearDownSuite() {
func (s *CephFlexDriverSuite) TearDownSuite() {
logger.Infof("Cleaning up block storage")
s.kh.DeletePods(
"setup-block-rwo", "setup-block-rwx", "rwo-block-rw-one", "rwo-block-rw-two", "rwo-block-ro-one",
"rwo-block-ro-two", "rwx-block-rw-one", "rwx-block-rw-two", "rwx-block-ro-one", "rwx-block-ro-two")
s.testClient.PoolClient.DeletePvc(s.namespace, s.pvcNameRWO)
s.testClient.PoolClient.DeletePvc(s.namespace, s.pvcNameRWX)
s.testClient.PoolClient.DeleteStorageClass("rook-ceph-block-rwo")
s.testClient.PoolClient.DeleteStorageClass("rook-ceph-block-rwx")
s.testClient.BlockClient.DeletePVC(s.namespace, s.pvcNameRWO)
s.testClient.BlockClient.DeletePVC(s.namespace, s.pvcNameRWX)
s.testClient.BlockClient.DeleteStorageClass("rook-ceph-block-rwo")
s.testClient.BlockClient.DeleteStorageClass("rook-ceph-block-rwx")
s.testClient.PoolClient.DeletePool(s.testClient.BlockClient, s.namespace, "block-pool-rwo")
s.testClient.PoolClient.DeletePool(s.testClient.BlockClient, s.namespace, "block-pool-rwx")
s.op.Teardown()
}
func (s *CephBlockSuite) TestBlockStorageMountUnMountForDifferentAccessModes() {
func (s *CephFlexDriverSuite) TestBlockStorageMountUnMountForDifferentAccessModes() {
s.setupPVCs()
logger.Infof("Test case when existing RWO PVC is mounted and unmounted on pods with various accessModes")
logger.Infof("Step 1.1: Mount existing ReadWriteOnce and ReadWriteMany PVC on a Pod with RW access")
// mount PVC with RWO access on a pod with readonly set to false
_, err := s.bc.BlockMap(getBlockPodDefinition("rwo-block-rw-one", s.pvcNameRWO, false))
err := s.bc.CreateClientPod(getFlexBlockPodDefinition("rwo-block-rw-one", s.pvcNameRWO, false))
require.Nil(s.T(), err)
// mount PVC with RWX access on a pod with readonly set to false
_, err = s.bc.BlockMap(getBlockPodDefinition("rwx-block-rw-one", s.pvcNameRWX, false))
err = s.bc.CreateClientPod(getFlexBlockPodDefinition("rwx-block-rw-one", s.pvcNameRWX, false))
require.Nil(s.T(), err)
crdName1, err1 := s.kh.GetVolumeResourceName(defaultNamespace, s.pvcNameRWO)
crdName2, err2 := s.kh.GetVolumeResourceName(defaultNamespace, s.pvcNameRWX)
assert.Nil(s.T(), err1)
assert.Nil(s.T(), err2)
assert.True(s.T(), s.kh.IsVolumeResourcePresent(installer.SystemNamespace(s.namespace), crdName1), fmt.Sprintf("make sure Volume %s is created", crdName1))
crdName, err := s.kh.GetVolumeResourceName(defaultNamespace, s.pvcNameRWO)
assert.Nil(s.T(), err)
assert.True(s.T(), s.kh.IsVolumeResourcePresent(installer.SystemNamespace(s.namespace), crdName), fmt.Sprintf("make sure Volume %s is created", crdName))
assert.True(s.T(), s.kh.IsPodRunning("rwo-block-rw-one", defaultNamespace), "make sure block-rw-one pod is in running state")
assert.True(s.T(), s.kh.IsVolumeResourcePresent(installer.SystemNamespace(s.namespace), crdName2), fmt.Sprintf("make sure Volume %s is created", crdName2))
crdName, err = s.kh.GetVolumeResourceName(defaultNamespace, s.pvcNameRWX)
assert.Nil(s.T(), err)
assert.True(s.T(), s.kh.IsVolumeResourcePresent(installer.SystemNamespace(s.namespace), crdName), fmt.Sprintf("make sure Volume %s is created", crdName))
assert.True(s.T(), s.kh.IsPodRunning("rwx-block-rw-one", defaultNamespace), "make sure rwx-block-rw-one pod is in running state")
logger.Infof("Step 2: Check if previously persisted data is readable from ReadWriteOnce and ReadWriteMany PVC")
@@ -278,10 +273,10 @@ func (s *CephBlockSuite) TestBlockStorageMountUnMountForDifferentAccessModes() {
// Mount another Pod with RW access on same PVC
logger.Infof("Step 4: Mount existing ReadWriteOnce and ReadWriteMany PVC on a new Pod with RW access")
// Mount RWO PVC on a new pod with ReadOnly set to false
_, err = s.bc.BlockMap(getBlockPodDefinition("rwo-block-rw-two", s.pvcNameRWO, false))
err = s.bc.CreateClientPod(getFlexBlockPodDefinition("rwo-block-rw-two", s.pvcNameRWO, false))
assert.Nil(s.T(), err)
// Mount RWX PVC on a new pod with ReadOnly set to false
_, err = s.bc.BlockMap(getBlockPodDefinition("rwx-block-rw-two", s.pvcNameRWX, false))
err = s.bc.CreateClientPod(getFlexBlockPodDefinition("rwx-block-rw-two", s.pvcNameRWX, false))
assert.Nil(s.T(), err)
assert.True(s.T(), s.kh.IsPodInError("rwo-block-rw-two", defaultNamespace, "FailedMount", "Volume is already attached by pod"), "make sure rwo-block-rw-two pod errors out while mounting the volume")
assert.True(s.T(), s.kh.IsPodInError("rwx-block-rw-two", defaultNamespace, "FailedMount", "Volume is already attached by pod"), "make sure rwx-block-rw-two pod errors out while mounting the volume")
@@ -292,10 +287,10 @@ func (s *CephBlockSuite) TestBlockStorageMountUnMountForDifferentAccessModes() {
logger.Infof("Step 5: Mount existing ReadWriteOnce and ReadWriteMany PVC on a new Pod with RO access")
// Mount RWO PVC on a new pod with ReadOnly set to true
_, err = s.bc.BlockMap(getBlockPodDefinition("rwo-block-ro-one", s.pvcNameRWO, true))
err = s.bc.CreateClientPod(getFlexBlockPodDefinition("rwo-block-ro-one", s.pvcNameRWO, true))
assert.Nil(s.T(), err)
// Mount RWX PVC on a new pod with ReadOnly set to true
_, err = s.bc.BlockMap(getBlockPodDefinition("rwx-block-ro-one", s.pvcNameRWX, true))
err = s.bc.CreateClientPod(getFlexBlockPodDefinition("rwx-block-ro-one", s.pvcNameRWX, true))
assert.Nil(s.T(), err)
assert.True(s.T(), s.kh.IsPodInError("rwo-block-ro-one", defaultNamespace, "FailedMount", "Volume is already attached by pod"), "make sure rwo-block-ro-one pod errors out while mounting the volume")
assert.True(s.T(), s.kh.IsPodInError("rwx-block-ro-one", defaultNamespace, "FailedMount", "Volume is already attached by pod"), "make sure rwx-block-ro-one pod errors out while mounting the volume")
@@ -311,16 +306,18 @@ func (s *CephBlockSuite) TestBlockStorageMountUnMountForDifferentAccessModes() {
assert.True(s.T(), s.kh.IsPodTerminated("rwx-block-rw-one", defaultNamespace), "make sure rwx-lock-rw-one pod is terminated")
logger.Infof("Step 7: Mount ReadWriteOnce and ReadWriteMany PVC on two different pods with ReadOnlyMany with Readonly Access")
// Mount RWO PVC on 2 pods with ReadOnly set to True
_, err1 = s.bc.BlockMap(getBlockPodDefinition("rwo-block-ro-one", s.pvcNameRWO, true))
_, err2 = s.bc.BlockMap(getBlockPodDefinition("rwo-block-ro-two", s.pvcNameRWO, true))
assert.Nil(s.T(), err1)
assert.Nil(s.T(), err2)
err = s.bc.CreateClientPod(getFlexBlockPodDefinition("rwo-block-ro-one", s.pvcNameRWO, true))
assert.Nil(s.T(), err)
err = s.bc.CreateClientPod(getFlexBlockPodDefinition("rwo-block-ro-two", s.pvcNameRWO, true))
assert.Nil(s.T(), err)
// Mount RWX PVC on 2 pods with ReadOnly set to True
_, err1 = s.bc.BlockMap(getBlockPodDefinition("rwx-block-ro-one", s.pvcNameRWX, true))
_, err2 = s.bc.BlockMap(getBlockPodDefinition("rwx-block-ro-two", s.pvcNameRWX, true))
assert.Nil(s.T(), err1)
assert.Nil(s.T(), err2)
err = s.bc.CreateClientPod(getFlexBlockPodDefinition("rwx-block-ro-one", s.pvcNameRWX, true))
assert.Nil(s.T(), err)
err = s.bc.CreateClientPod(getFlexBlockPodDefinition("rwx-block-ro-two", s.pvcNameRWX, true))
assert.Nil(s.T(), err)
assert.True(s.T(), s.kh.IsPodRunning("rwo-block-ro-one", defaultNamespace), "make sure rwo-block-ro-one pod is in running state")
assert.True(s.T(), s.kh.IsPodRunning("rwo-block-ro-two", defaultNamespace), "make sure rwo-block-ro-two pod is in running state")
assert.True(s.T(), s.kh.IsPodRunning("rwx-block-ro-one", defaultNamespace), "make sure rwx-block-ro-one pod is in running state")
@@ -354,4 +351,46 @@ func (s *CephBlockSuite) TestBlockStorageMountUnMountForDifferentAccessModes() {
assert.True(s.T(), s.kh.IsPodTerminated("rwo-block-ro-two", defaultNamespace), "make sure rwo-block-ro-two pod is terminated")
assert.True(s.T(), s.kh.IsPodTerminated("rwx-block-ro-one", defaultNamespace), "make sure rwx-lock-ro-one pod is terminated")
assert.True(s.T(), s.kh.IsPodTerminated("rwx-block-ro-two", defaultNamespace), "make sure rwx-block-ro-two pod is terminated")
// Test volume expansion
v := version.MustParseSemantic(s.kh.GetK8sServerVersion())
if v.AtLeast(version.MustParseSemantic("1.15.0")) {
logger.Infof("additional step: Expand block storage")
// Expanding the image by applying new PVC specs
err := s.testClient.BlockClient.CreatePVC(defaultNamespace, s.pvcNameRWO, "rook-ceph-block-rwo", "ReadWriteOnce", "2M")
require.Nil(s.T(), err)
// Once the pod using the volume is terminated, the filesystem is expanded and the size of the PVC is increased.
expandedPodName := "setup-block-rwo"
err = s.kh.DeletePod(defaultNamespace, expandedPodName)
require.Nil(s.T(), err)
err = s.bc.CreateClientPod(getFlexBlockPodDefinition(expandedPodName, s.pvcNameRWO, false))
require.Nil(s.T(), err)
require.True(s.T(), s.kh.IsPodRunning(expandedPodName, defaultNamespace), "Make sure new pod is running")
require.True(s.T(), s.kh.WaitUntilPVCIsExpanded(defaultNamespace, s.pvcNameRWO, "2M"), "Make sure PVC is expanded")
logger.Infof("Block Storage successfully expanded")
}
}
func getFlexBlockPodDefinition(podName, blockName string, readOnly bool) string {
return `apiVersion: v1
kind: Pod
metadata:
name: ` + podName + `
spec:
containers:
- image: busybox
name: block-test1
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
volumeMounts:
- name: block-persistent-storage
mountPath: ` + utils.TestMountPath + `
volumes:
- name: block-persistent-storage
persistentVolumeClaim:
claimName: ` + blockName + `
readOnly: ` + strconv.FormatBool(readOnly) + `
restartPolicy: Never`
}
+3 -5
View File
@@ -82,19 +82,17 @@ func (hs *HelmSuite) AfterTest(suiteName, testName string) {
}
// Test to make sure all rook components are installed and Running
func (hs *HelmSuite) TestRookInstallViaHelm() {
func (hs *HelmSuite) TestARookInstallViaHelm() {
checkIfRookClusterIsInstalled(hs.Suite, hs.kh, hs.namespace, hs.namespace, 1)
}
// Test BlockCreation on Rook that was installed via Helm
func (hs *HelmSuite) TestBlockStoreOnRookInstalledViaHelm() {
runBlockE2ETestLite(hs.helper, hs.kh, hs.Suite, hs.namespace, hs.op.installer.CephVersion)
runBlockCSITestLite(hs.helper, hs.kh, hs.Suite, hs.namespace, hs.namespace, hs.op.installer.CephVersion)
}
// Test File System Creation on Rook that was installed via helm
// The test func name has `Z` in its name to run as the last test, this needs to
// be done as there were some issues that the operator "disappeared".
func (hs *HelmSuite) TestZFileStoreOnRookInstalledViaHelm() {
func (hs *HelmSuite) TestFileStoreOnRookInstalledViaHelm() {
runFileE2ETestLite(hs.helper, hs.kh, hs.Suite, hs.namespace, "testfs")
}
-104
View File
@@ -1,104 +0,0 @@
/*
Copyright 2016 The Rook Authors. All rights reserved.
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 integration
import (
"strings"
"time"
appsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func (suite *SmokeSuite) getNonCanaryMonDeployments() ([]appsv1.Deployment, error) {
opts := metav1.ListOptions{LabelSelector: "app=rook-ceph-mon"}
deployments, err := suite.k8sh.Clientset.AppsV1().Deployments(suite.namespace).List(opts)
if err != nil {
return nil, err
}
nonCanaryMonDeployments := []appsv1.Deployment{}
for _, deployment := range deployments.Items {
if !strings.HasSuffix(deployment.GetName(), "-canary") {
nonCanaryMonDeployments = append(nonCanaryMonDeployments, deployment)
}
}
return nonCanaryMonDeployments, nil
}
// Smoke Test for Mon failover - Test check the following operations for the Mon failover in order
// Delete mon pod, Wait for new mon pod
func (suite *SmokeSuite) TestMonFailover() {
logger.Infof("Mon Failover Smoke Test")
deployments, err := suite.getNonCanaryMonDeployments()
require.Nil(suite.T(), err)
require.Equal(suite.T(), 3, len(deployments))
monToKill := deployments[0].Name
logger.Infof("Killing mon %s", monToKill)
propagation := metav1.DeletePropagationForeground
delOptions := &metav1.DeleteOptions{PropagationPolicy: &propagation}
err = suite.k8sh.Clientset.AppsV1().Deployments(suite.namespace).Delete(monToKill, delOptions)
require.Nil(suite.T(), err)
// Wait for the health check to start a new monitor
originalMonDeleted := false
for i := 0; i < 30; i++ {
deployments, err := suite.getNonCanaryMonDeployments()
require.Nil(suite.T(), err)
// Make sure the old mon is not still alive
foundOldMon := false
for _, mon := range deployments {
if mon.Name == monToKill {
foundOldMon = true
}
}
// Check if we have three monitors
if foundOldMon {
if originalMonDeleted {
// Depending on the state of the orchestration, the operator might trigger
// re-creation of the deleted mon. In this case, consider the test successful
// rather than wait for the failover which will never occur.
logger.Infof("Original mon created again, no need to wait for mon failover")
return
}
logger.Infof("Waiting for old monitor to stop")
} else {
logger.Infof("Waiting for a new monitor to start")
originalMonDeleted = true
if len(deployments) == 3 {
var newMons []string
for _, mon := range deployments {
newMons = append(newMons, mon.Name)
}
logger.Infof("Found a new monitor! monitors=%v", newMons)
return
}
assert.Equal(suite.T(), 2, len(deployments))
}
time.Sleep(5 * time.Second)
}
require.Fail(suite.T(), "giving up waiting for a new monitor")
}
+1 -1
View File
@@ -172,7 +172,7 @@ func (o MCTestOperations) Teardown() {
func (o MCTestOperations) startCluster(namespace, store string) error {
logger.Infof("starting cluster %s", namespace)
err := o.installer.CreateK8sRookClusterWithHostPathAndDevicesOrPVC(namespace, o.systemNamespace, store, o.testOverPVC, o.storageClassName,
cephv1.MonSpec{Count: 3, AllowMultiplePerNode: true}, true, 1, installer.NautilusVersion)
cephv1.MonSpec{Count: 1, AllowMultiplePerNode: true}, true, 1, installer.NautilusVersion)
if err != nil {
o.T().Fail()
o.installer.GatherAllRookLogs(o.T().Name(), namespace, o.systemNamespace)
-78
View File
@@ -1,78 +0,0 @@
/*
Copyright 2017 The Rook Authors. All rights reserved.
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 integration
import (
"fmt"
"time"
"github.com/stretchr/testify/require"
)
// Smoke Test for pool Resizing
func (suite *SmokeSuite) TestPoolResize() {
logger.Infof("Pool Resize Smoke Test")
poolName := "testpool"
err := suite.helper.PoolClient.Create(poolName, suite.namespace, 1)
require.Nil(suite.T(), err)
poolFound := false
// Wait for pool to appear
for i := 0; i < 10; i++ {
pools, err := suite.helper.PoolClient.ListCephPools(suite.namespace)
require.Nil(suite.T(), err)
for _, p := range pools {
if p.Name != poolName {
continue
}
poolFound = true
}
if poolFound {
break
}
logger.Infof("Waiting for pool to appear")
time.Sleep(2 * time.Second)
}
require.Equal(suite.T(), true, poolFound, "pool not found")
err = suite.helper.PoolClient.Update(poolName, suite.namespace, 3)
require.Nil(suite.T(), err)
poolFound = false
// Wait for pool resize to happen
for i := 0; i < 10; i++ {
details, err := suite.helper.PoolClient.GetCephPoolDetails(suite.namespace, poolName)
require.Nil(suite.T(), err)
if details.Size > 1 {
logger.Infof("pool %s size got updated", poolName)
require.Equal(suite.T(), 3, int(details.Size))
poolFound = true
break
}
logger.Infof("pool %s size not updated yet. details: %+v", poolName, details)
logger.Infof("Waiting for pool %s resize to happen", poolName)
time.Sleep(2 * time.Second)
}
require.Equal(suite.T(), true, poolFound, fmt.Sprintf("pool %s not found", poolName))
}
+185 -7
View File
@@ -17,12 +17,19 @@ limitations under the License.
package integration
import (
"fmt"
"strings"
"testing"
"time"
"github.com/rook/rook/tests/framework/clients"
"github.com/rook/rook/tests/framework/installer"
"github.com/rook/rook/tests/framework/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
appsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// ************************************************
@@ -85,16 +92,13 @@ func (suite *SmokeSuite) TearDownSuite() {
suite.op.Teardown()
}
func (suite *SmokeSuite) TestBlockCSI_SmokeTest() {
runCephCSIE2ETest(suite.helper, suite.k8sh, suite.Suite, suite.op.T(), suite.namespace)
}
func (suite *SmokeSuite) TestBlockStorage_SmokeTest() {
runBlockE2ETest(suite.helper, suite.k8sh, suite.Suite, suite.namespace)
runBlockCSITest(suite.helper, suite.k8sh, suite.Suite, suite.namespace)
}
func (suite *SmokeSuite) TestFileStorage_SmokeTest() {
runFileE2ETest(suite.helper, suite.k8sh, suite.Suite, suite.namespace, "smoke-test-fs")
useCSI := true
runFileE2ETest(suite.helper, suite.k8sh, suite.Suite, suite.namespace, "smoke-test-fs", useCSI)
}
func (suite *SmokeSuite) TestObjectStorage_SmokeTest() {
@@ -102,6 +106,180 @@ func (suite *SmokeSuite) TestObjectStorage_SmokeTest() {
}
// Test to make sure all rook components are installed and Running
func (suite *SmokeSuite) TestRookClusterInstallation_SmokeTest() {
func (suite *SmokeSuite) TestARookClusterInstallation_SmokeTest() {
checkIfRookClusterIsInstalled(suite.Suite, suite.k8sh, installer.SystemNamespace(suite.namespace), suite.namespace, 3)
}
// Smoke Test for Mon failover - Test check the following operations for the Mon failover in order
// Delete mon pod, Wait for new mon pod
func (suite *SmokeSuite) TestMonFailover() {
logger.Infof("Mon Failover Smoke Test")
deployments, err := suite.getNonCanaryMonDeployments()
require.Nil(suite.T(), err)
require.Equal(suite.T(), 3, len(deployments))
monToKill := deployments[0].Name
logger.Infof("Killing mon %s", monToKill)
propagation := metav1.DeletePropagationForeground
delOptions := &metav1.DeleteOptions{PropagationPolicy: &propagation}
err = suite.k8sh.Clientset.AppsV1().Deployments(suite.namespace).Delete(monToKill, delOptions)
require.Nil(suite.T(), err)
// Wait for the health check to start a new monitor
originalMonDeleted := false
for i := 0; i < 30; i++ {
deployments, err := suite.getNonCanaryMonDeployments()
require.Nil(suite.T(), err)
// Make sure the old mon is not still alive
foundOldMon := false
for _, mon := range deployments {
if mon.Name == monToKill {
foundOldMon = true
}
}
// Check if we have three monitors
if foundOldMon {
if originalMonDeleted {
// Depending on the state of the orchestration, the operator might trigger
// re-creation of the deleted mon. In this case, consider the test successful
// rather than wait for the failover which will never occur.
logger.Infof("Original mon created again, no need to wait for mon failover")
return
}
logger.Infof("Waiting for old monitor to stop")
} else {
logger.Infof("Waiting for a new monitor to start")
originalMonDeleted = true
if len(deployments) == 3 {
var newMons []string
for _, mon := range deployments {
newMons = append(newMons, mon.Name)
}
logger.Infof("Found a new monitor! monitors=%v", newMons)
return
}
assert.Equal(suite.T(), 2, len(deployments))
}
time.Sleep(5 * time.Second)
}
require.Fail(suite.T(), "giving up waiting for a new monitor")
}
// Smoke Test for pool Resizing
func (suite *SmokeSuite) TestPoolResize() {
logger.Infof("Pool Resize Smoke Test")
poolName := "testpool"
err := suite.helper.PoolClient.Create(poolName, suite.namespace, 1)
require.Nil(suite.T(), err)
poolFound := false
// Wait for pool to appear
for i := 0; i < 10; i++ {
pools, err := suite.helper.PoolClient.ListCephPools(suite.namespace)
require.Nil(suite.T(), err)
for _, p := range pools {
if p.Name != poolName {
continue
}
poolFound = true
}
if poolFound {
break
}
logger.Infof("Waiting for pool to appear")
time.Sleep(2 * time.Second)
}
require.Equal(suite.T(), true, poolFound, "pool not found")
err = suite.helper.PoolClient.Update(poolName, suite.namespace, 3)
require.Nil(suite.T(), err)
poolFound = false
// Wait for pool resize to happen
for i := 0; i < 10; i++ {
details, err := suite.helper.PoolClient.GetCephPoolDetails(suite.namespace, poolName)
require.Nil(suite.T(), err)
if details.Size > 1 {
logger.Infof("pool %s size got updated", poolName)
require.Equal(suite.T(), 3, int(details.Size))
poolFound = true
break
}
logger.Infof("pool %s size not updated yet. details: %+v", poolName, details)
logger.Infof("Waiting for pool %s resize to happen", poolName)
time.Sleep(2 * time.Second)
}
require.Equal(suite.T(), true, poolFound, fmt.Sprintf("pool %s not found", poolName))
}
// Smoke Test for Client CRD
func (suite *SmokeSuite) TestCreateClient() {
logger.Infof("Create Client Smoke Test")
clientName := "client1"
caps := map[string]string{
"mon": "allow rwx",
"mgr": "allow rwx",
"osd": "allow rwx",
}
err := suite.helper.UserClient.Create(clientName, suite.namespace, caps)
require.Nil(suite.T(), err)
clientFound := false
for i := 0; i < 30; i++ {
clients, _ := suite.helper.UserClient.Get(suite.namespace, "client."+clientName)
if clients != "" {
clientFound = true
}
if clientFound {
break
}
logger.Infof("Waiting for client to appear")
time.Sleep(2 * time.Second)
}
require.Equal(suite.T(), true, clientFound, "client not found")
logger.Infof("Update Client Smoke Test")
newcaps := map[string]string{
"mon": "allow r",
"mgr": "allow rw",
"osd": "allow *",
}
caps, _ = suite.helper.UserClient.Update(suite.namespace, clientName, newcaps)
require.Equal(suite.T(), "allow r", caps["mon"], "wrong caps")
require.Equal(suite.T(), "allow rw", caps["mgr"], "wrong caps")
require.Equal(suite.T(), "allow *", caps["osd"], "wrong caps")
}
func (suite *SmokeSuite) getNonCanaryMonDeployments() ([]appsv1.Deployment, error) {
opts := metav1.ListOptions{LabelSelector: "app=rook-ceph-mon"}
deployments, err := suite.k8sh.Clientset.AppsV1().Deployments(suite.namespace).List(opts)
if err != nil {
return nil, err
}
nonCanaryMonDeployments := []appsv1.Deployment{}
for _, deployment := range deployments.Items {
if !strings.HasSuffix(deployment.GetName(), "-canary") {
nonCanaryMonDeployments = append(nonCanaryMonDeployments, deployment)
}
}
return nonCanaryMonDeployments, nil
}
+63 -39
View File
@@ -89,28 +89,31 @@ func (s *UpgradeSuite) TearDownSuite() {
}
func (s *UpgradeSuite) TestUpgradeToMaster() {
checkSkipCSITest(s.Suite, s.k8sh)
systemNamespace := installer.SystemNamespace(s.namespace)
//
// Create block, object, and file storage on 1.0 before the upgrade
// Create block, object, and file storage before the upgrade
//
poolName := "upgradepool"
storageClassName := "block-upgrade"
blockName := "block-claim-upgrade"
logger.Infof("Initializing block before the upgrade")
setupBlockLite(s.helper, s.k8sh, s.Suite, s.namespace, poolName, storageClassName, blockName, rbdPodName, s.op.installer.CephVersion)
createPodWithBlock(s.helper, s.k8sh, s.Suite, s.namespace, blockName, rbdPodName)
defer blockTestDataCleanUp(s.helper, s.k8sh, s.Suite, s.namespace, poolName, storageClassName, blockName, rbdPodName)
setupBlockLite(s.helper, s.k8sh, s.Suite, s.namespace, systemNamespace, poolName, storageClassName, blockName, rbdPodName, s.op.installer.CephVersion)
createPodWithBlock(s.helper, s.k8sh, s.Suite, s.namespace, storageClassName, rbdPodName, blockName)
// FIX: We should require block images to be removed. See tracking issue:
// <INSERT ISSUE>
requireBlockImagesRemoved := false
defer blockTestDataCleanUp(s.helper, s.k8sh, s.Suite, s.namespace, poolName, storageClassName, blockName, rbdPodName, requireBlockImagesRemoved)
// Create the filesystem, but wait to create the file test client until we upgrade to nautilus
logger.Infof("Initializing file before the upgrade")
filesystemName := "upgrade-test-fs"
activeCount := 1
createFilesystem(s.helper, s.k8sh, s.Suite, s.namespace, filesystemName, activeCount)
createFilesystemConsumerPod(s.helper, s.k8sh, s.Suite, s.namespace, filesystemName)
defer func() {
cleanupFilesystemConsumer(s.k8sh, s.Suite, s.namespace, filePodName)
cleanupFilesystem(s.helper, s.k8sh, s.Suite, s.namespace, filesystemName)
}()
logger.Infof("Initializing object before the upgrade")
objectStoreName := "upgraded-object"
@@ -123,11 +126,10 @@ func (s *UpgradeSuite) TestUpgradeToMaster() {
preFilename := "pre-upgrade-file"
assert.NoError(s.T(), s.k8sh.WriteToPod("", rbdPodName, preFilename, message))
assert.NoError(s.T(), s.k8sh.ReadFromPod("", rbdPodName, preFilename, message))
assert.NoError(s.T(), s.k8sh.WriteToPod(s.namespace, filePodName, preFilename, message))
assert.NoError(s.T(), s.k8sh.ReadFromPod(s.namespace, filePodName, preFilename, message))
// we will keep appending to this to continue verifying old files through the upgrades
oldFilesToRead := []string{preFilename}
rbdFilesToRead := []string{preFilename}
cephfsFilesToRead := []string{}
// Get some info about the currently deployed OSDs to determine later if they are all updated
osdDepList, err := k8sutil.GetDeployments(s.k8sh.Clientset, s.namespace, "app=rook-ceph-osd")
@@ -147,8 +149,8 @@ func (s *UpgradeSuite) TestUpgradeToMaster() {
s.verifyRookUpgrade(numOSDs)
logger.Infof("Done with automatic upgrade from v1.1 to v1.2")
newFile := "post-upgrade-1_1-to-1_2-file"
s.verifyFilesAfterUpgrade(filesystemName, newFile, message, oldFilesToRead)
oldFilesToRead = append(oldFilesToRead, newFile)
s.verifyFilesAfterUpgrade("", newFile, message, rbdFilesToRead, cephfsFilesToRead)
rbdFilesToRead = append(rbdFilesToRead, newFile)
logger.Infof("Verified upgrade from v1.1 to v1.2")
//
@@ -157,9 +159,22 @@ func (s *UpgradeSuite) TestUpgradeToMaster() {
logger.Infof("*** UPGRADING CEPH FROM Mimic TO Nautilus ***")
s.gatherLogs(systemNamespace, "_before_ceph_upgrade")
s.upgradeCephVersion(installer.NautilusVersion.Image, numOSDs)
// Start the file test client now that the CSI driver is supported on nautilus
fsStorageClass := "file-upgrade"
assert.NoError(s.T(), s.helper.FSClient.CreateStorageClass(filesystemName, s.namespace, fsStorageClass))
useCSI := true
createFilesystemConsumerPod(s.helper, s.k8sh, s.Suite, s.namespace, filesystemName, fsStorageClass, useCSI)
defer func() {
cleanupFilesystemConsumer(s.helper, s.k8sh, s.Suite, s.namespace, filePodName)
cleanupFilesystem(s.helper, s.k8sh, s.Suite, s.namespace, filesystemName)
}()
// Verify reading and writing to the test clients
newFile = "post-ceph-upgrade-file"
s.verifyFilesAfterUpgrade(filesystemName, newFile, message, oldFilesToRead)
oldFilesToRead = append(oldFilesToRead, newFile)
s.verifyFilesAfterUpgrade(filesystemName, newFile, message, rbdFilesToRead, cephfsFilesToRead)
rbdFilesToRead = append(rbdFilesToRead, newFile)
cephfsFilesToRead = append(cephfsFilesToRead, newFile)
logger.Infof("Verified upgrade from mimic to nautilus")
//
@@ -173,8 +188,9 @@ func (s *UpgradeSuite) TestUpgradeToMaster() {
s.verifyRookUpgrade(numOSDs)
logger.Infof("Done with automatic upgrade from v1.2 to master")
newFile = "post-upgrade-1_2-to-master-file"
s.verifyFilesAfterUpgrade(filesystemName, newFile, message, oldFilesToRead)
oldFilesToRead = append(oldFilesToRead, newFile)
s.verifyFilesAfterUpgrade(filesystemName, newFile, message, rbdFilesToRead, cephfsFilesToRead)
rbdFilesToRead = append(rbdFilesToRead, newFile)
cephfsFilesToRead = append(cephfsFilesToRead, newFile)
logger.Infof("Verified upgrade from v1.2 to master")
}
@@ -198,7 +214,7 @@ func (s *UpgradeSuite) upgradeCephVersion(newCephImage string, numOSDs int) {
s.k8sh.Kubectl("-n", s.namespace, "patch", "CephCluster", s.namespace, "--type=merge",
"-p", fmt.Sprintf(`{"spec": {"cephVersion": {"image": "%s"}}}`, newCephImage))
s.waitForUpgradedDaemons(oldCephVersion, "ceph-version", numOSDs)
s.waitForUpgradedDaemons(oldCephVersion, "ceph-version", numOSDs, false)
}
func (s *UpgradeSuite) verifyOperatorImage(expectedImage string) {
@@ -230,10 +246,10 @@ func (s *UpgradeSuite) verifyRookUpgrade(numOSDs int) {
d := osdDepList.Items[0]
oldRookVersion := d.Labels["rook-version"] // upgraded OSDs should not have this version label
s.waitForUpgradedDaemons(oldRookVersion, "rook-version", numOSDs)
s.waitForUpgradedDaemons(oldRookVersion, "rook-version", numOSDs, true)
}
func (s *UpgradeSuite) waitForUpgradedDaemons(previousVersion, versionLabel string, numOSDs int) {
func (s *UpgradeSuite) waitForUpgradedDaemons(previousVersion, versionLabel string, numOSDs int, waitForMDS bool) {
// wait for the mon(s) to be updated
monsNotOldVersion := fmt.Sprintf("app=rook-ceph-mon,%s!=%s", versionLabel, previousVersion)
err := s.k8sh.WaitForDeploymentCount(monsNotOldVersion, s.namespace, s.op.mons)
@@ -256,11 +272,15 @@ func (s *UpgradeSuite) waitForUpgradedDaemons(previousVersion, versionLabel stri
require.NoError(s.T(), err)
// wait for the mds pods to be updated
mdsesNotOldVersion := fmt.Sprintf("app=rook-ceph-mds,%s!=%s", versionLabel, previousVersion)
err = s.k8sh.WaitForDeploymentCount(mdsesNotOldVersion, s.namespace, 2 /* always expect 2 mdses */)
require.NoError(s.T(), err)
err = s.k8sh.WaitForLabeledDeploymentsToBeReady(mdsesNotOldVersion, s.namespace)
require.NoError(s.T(), err)
// FIX: In v1.2 there was a race condition that can cause the MDS to not be updated, so we skip
// the check for MDS upgrade in case it's just a ceph upgrade (no operator restart)
if waitForMDS {
mdsesNotOldVersion := fmt.Sprintf("app=rook-ceph-mds,%s!=%s", versionLabel, previousVersion)
err = s.k8sh.WaitForDeploymentCount(mdsesNotOldVersion, s.namespace, 2 /* always expect 2 mdses */)
require.NoError(s.T(), err)
err = s.k8sh.WaitForLabeledDeploymentsToBeReady(mdsesNotOldVersion, s.namespace)
require.NoError(s.T(), err)
}
rgwsNotOldVersion := fmt.Sprintf("app=rook-ceph-rgw,%s!=%s", versionLabel, previousVersion)
err = s.k8sh.WaitForDeploymentCount(rgwsNotOldVersion, s.namespace, 1 /* always expect 1 rgw */)
@@ -272,29 +292,33 @@ func (s *UpgradeSuite) waitForUpgradedDaemons(previousVersion, versionLabel stri
time.Sleep(5 * time.Second)
}
func (s *UpgradeSuite) verifyFilesAfterUpgrade(fsName, newFileToWrite, messageForAllFiles string, oldFilesToRead []string) {
func (s *UpgradeSuite) verifyFilesAfterUpgrade(fsName, newFileToWrite, messageForAllFiles string, rbdFilesToRead, cephFSFilesToRead []string) {
retryCount := 5
// wait for filesystem to be active
err := waitForFilesystemActive(s.k8sh, s.namespace, fsName)
require.NoError(s.T(), err)
for _, file := range oldFilesToRead {
// test reading preexisting files in the pod with cephfs mounted
assert.NoError(s.T(), s.k8sh.ReadFromPodRetry(s.namespace, filePodName, file, messageForAllFiles, retryCount))
for _, file := range rbdFilesToRead {
// test reading preexisting files in the pod with rbd mounted
// There is some unreliability right after the upgrade when there is only one osd, so we will retry if needed
assert.NoError(s.T(), s.k8sh.ReadFromPodRetry("", rbdPodName, file, messageForAllFiles, retryCount))
}
// test writing and reading a new file in the pod with cephfs mounted
assert.NoError(s.T(), s.k8sh.WriteToPodRetry(s.namespace, filePodName, newFileToWrite, messageForAllFiles, retryCount))
assert.NoError(s.T(), s.k8sh.ReadFromPodRetry(s.namespace, filePodName, newFileToWrite, messageForAllFiles, retryCount))
// test writing and reading a new file in the pod with rbd mounted
assert.NoError(s.T(), s.k8sh.WriteToPodRetry("", rbdPodName, newFileToWrite, messageForAllFiles, retryCount))
assert.NoError(s.T(), s.k8sh.ReadFromPodRetry("", rbdPodName, newFileToWrite, messageForAllFiles, retryCount))
if fsName != "" {
// wait for filesystem to be active
err := waitForFilesystemActive(s.k8sh, s.namespace, fsName)
require.NoError(s.T(), err)
// test reading preexisting files in the pod with cephfs mounted
for _, file := range cephFSFilesToRead {
assert.NoError(s.T(), s.k8sh.ReadFromPodRetry(s.namespace, filePodName, file, messageForAllFiles, retryCount))
}
// test writing and reading a new file in the pod with cephfs mounted
assert.NoError(s.T(), s.k8sh.WriteToPodRetry(s.namespace, filePodName, newFileToWrite, messageForAllFiles, retryCount))
assert.NoError(s.T(), s.k8sh.ReadFromPodRetry(s.namespace, filePodName, newFileToWrite, messageForAllFiles, retryCount))
}
}
// UpgradeToV1_2 performs the steps necessary to upgrade a Rook v1.1 cluster to v1.2. It does not
+1 -3
View File
@@ -120,16 +120,14 @@ func (suite *CockroachDBSuite) TestCockroachDBClusterInstallation() {
`create database if not exists rookcockroachdb; use rookcockroachdb; create table if not exists testtable ( testID int ); insert into testtable values (123456789); select * from testtable;`,
}
inc := 0
var result string
for inc < utils.RetryLoop {
for i := 0; i < utils.RetryLoop; i++ {
result, err = suite.k8shelper.Exec(suite.systemNamespace, operatorPodName, command, commandArgs)
logger.Infof("cockroachdb sql command exited, err: %+v. result: %s", err, result)
if err == nil {
break
}
logger.Warning("cockroachdb sql command failed, will try again")
inc++
time.Sleep(utils.RetryInterval * time.Second)
}
+1 -3
View File
@@ -126,11 +126,10 @@ func (suite *NfsSuite) TestNfsServerInstallation() {
}
func (suite *NfsSuite) checkReadData(podList []string) bool {
inc := 0
var result string
var err error
// the following for loop retries to read data from the first pod in the pod list
for inc < utils.RetryLoop {
for i := 0; i < utils.RetryLoop; i++ {
// the nfs volume is mounted on "/mnt" and the data(hostname of the pod) is written in "/mnt/data" of the pod
// results stores the hostname of either one of the pod which is same as the pod name, which is read from "/mnt/data"
result, err = suite.rwClient.Read(podList[0])
@@ -139,7 +138,6 @@ func (suite *NfsSuite) checkReadData(podList []string) bool {
break
}
logger.Warning("nfs volume read failed, will try again")
inc++
time.Sleep(utils.RetryInterval * time.Second)
}
require.NoError(suite.T(), err)
+1 -1
View File
@@ -162,7 +162,7 @@ SELECT key,value FROM map WHERE key='test_key';`,
time.Sleep(30 * time.Second)
var result string
for inc := 0; inc < utils.RetryLoop; inc++ {
for i := 0; i < utils.RetryLoop; i++ {
result, err = s.k8sHelper.Exec(s.namespace, podName, command, commandArgs)
logger.Infof("cassandra cql command exited, err: %v. result: %s", err, result)
if err == nil {
-274
View File
@@ -1,274 +0,0 @@
package longhaul
import (
"strings"
"sync"
"testing"
"time"
cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
"github.com/rook/rook/tests/framework/clients"
"github.com/rook/rook/tests/framework/installer"
"github.com/rook/rook/tests/framework/utils"
"github.com/stretchr/testify/require"
)
var (
defaultNamespace = "default"
)
// Create StorageClass and poll if needed
func createStorageClassAndPool(t func() *testing.T, testClient *clients.TestClient, kh *utils.K8sHelper, namespace string, storageClassName string, poolName string) {
// Create storage class
if err := kh.IsStorageClassPresent(storageClassName); err != nil {
logger.Infof("Install pool and storage class for rook block")
err := testClient.PoolClient.Create(poolName, namespace, 3)
require.NoError(t(), err)
err = testClient.BlockClient.CreateStorageClass(poolName, storageClassName, "Delete", namespace, false)
require.NoError(t(), err)
// make sure storageclass is created
err = kh.IsStorageClassPresent(storageClassName)
require.NoError(t(), err)
}
}
// Set Up rook, storageClass ,pvc and mysql pods for longhaul test
// All the set up is if needed.
func createPVCAndMountMysqlPod(t func() *testing.T, kh *utils.K8sHelper, storageClassName string, appName string, appLabel string, pvcName string) *utils.MySQLHelper {
// Create mysql pod
if _, err := kh.GetPVCStatus(defaultNamespace, pvcName); err != nil {
logger.Infof("Create PVC")
mySqlPodOperation(kh, storageClassName, appName, appLabel, pvcName, "apply")
// Wait till mysql pod is up
require.True(t(), kh.IsPodInExpectedState(appLabel, "", "Running"))
require.True(t(), kh.WaitUntilPVCIsBound(defaultNamespace, pvcName))
}
dbIP, err := kh.GetPodHostID(appLabel, "")
require.Nil(t(), err)
dbPort, err := kh.GetServiceNodePort(appName, "default")
require.Nil(t(), err)
// Create database connection
db := utils.CreateNewMySQLHelper("mysql", "mysql", dbIP+":"+dbPort, "sample")
require.True(t(), db.PingSuccess())
if exist := db.TableExists(); !exist {
db.CreateTable()
}
return db
}
func mySqlPodOperation(k8sh *utils.K8sHelper, storageClassName string, appName string, appLabel string, pvcName string, action string) (string, error) {
config := map[string]string{
"appName": appName,
"appLabel": appLabel,
"storageClassName": storageClassName,
"pvcName": pvcName,
}
result, err := k8sh.ResourceOperationFromTemplate(action, GetMySqlPodDef(), config)
return result, err
}
func mountUnmountPVCOnPod(k8sh *utils.K8sHelper, podName string, pvcName string, readonly string, action string) (string, error) {
config := map[string]string{
"podName": podName,
"pvcName": pvcName,
"readOnly": readonly,
}
result, err := k8sh.ResourceOperationFromTemplate(action, getBlockPodDefinition(), config)
return result, err
}
func performBlockOperations(db *utils.MySQLHelper) {
var wg sync.WaitGroup
for i := 1; i <= installer.Env.LoadConcurrentRuns; i++ {
wg.Add(1)
go dbOperation(db, &wg, installer.Env.LoadTime, installer.Env.LoadSize)
}
wg.Wait()
}
func dbOperation(db *utils.MySQLHelper, wg *sync.WaitGroup, runtime int, loadSize string) {
defer wg.Done()
ds := 100000
switch strings.ToLower(loadSize) {
case "small":
ds = 105000 //.1M * 5 columns * 6 = 3M per thread
case "medium":
ds = 419430 // .4M * 5 columns * 6 = 12M per thread
case "large":
ds = 2100000 // 2M * 5 columns * 6 = 60M per thread
default:
ds = 209715 // .2M * 5 columns * 6 = 15M per thread
}
start := time.Now()
elapsed := time.Since(start).Seconds()
for elapsed < float64(runtime) {
// InsertRandomData
db.InsertRandomData(ds)
db.InsertRandomData(ds)
db.InsertRandomData(ds)
db.SelectRandomData(5)
db.InsertRandomData(ds)
db.InsertRandomData(ds)
db.InsertRandomData(ds)
db.SelectRandomData(10)
// Delete Data
db.DeleteRandomRow()
db.SelectRandomData(20)
elapsed = time.Since(start).Seconds()
}
}
// LoadTestCluster struct for handling panic and test suite tear down
type LoadTestCluster struct {
installer *installer.CephInstaller
kh *utils.K8sHelper
helper *clients.TestClient
T func() *testing.T
namespace string
}
// StartLoadTestCluster creates new instance of TestCluster struct
func StartLoadTestCluster(t func() *testing.T, namespace string) (LoadTestCluster, *utils.K8sHelper, *installer.CephInstaller) {
kh, err := utils.CreateK8sHelper(t)
require.NoError(t(), err)
i := installer.NewCephInstaller(t, kh.Clientset, false, installer.VersionMaster, cephv1.CephVersionSpec{Image: "ceph/ceph:v14.2.6"})
op := LoadTestCluster{i, kh, nil, t, namespace}
op.Setup()
return op, kh, i
}
// Setup is a wrapper for setting up rook
func (o LoadTestCluster) Setup() {
if !o.kh.IsRookInstalled(o.namespace) {
isRookInstalled, err := o.installer.InstallRookOnK8sWithHostPathAndDevicesOrPVC(o.namespace, "bluestore", false, "",
cephv1.MonSpec{Count: 3, AllowMultiplePerNode: true},
true, /* startWithAllNodes */
1 /*rbd mirror workers*/)
require.NoError(o.T(), err)
require.True(o.T(), isRookInstalled)
}
// Enable chaos monkey if enable_chaos flag is present
if installer.Env.EnableChaos {
c := NewChaosHelper(o.namespace, o.kh)
go c.Monkey()
}
}
// TearDownRook is a wrapper for tearDown after suite
func (o LoadTestCluster) Teardown() {
// No Clean up for load test
}
func GetMySqlPodDef() string {
return `apiVersion: v1
kind: Service
metadata:
name: {{.appName}}
labels:
app: {{.appLabel}}
spec:
ports:
- port: 3306
targetPort: 3306
protocol: TCP
selector:
app: {{.appLabel}}
tier: mysql
type: NodePort
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{.pvcName}}
labels:
app: {{.appLabel}}
spec:
storageClassName: {{.storageClassName}}
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{.appName}}
labels:
app: {{.appLabel}}
spec:
strategy:
type: Recreate
selector:
matchLabels:
app: {{.appLabel}}
template:
metadata:
labels:
app: {{.appLabel}}
tier: mysql
spec:
containers:
- image: mysql:5.6
name: mysql
env:
- name: "MYSQL_USER"
value: "mysql"
- name: "MYSQL_PASSWORD"
value: "mysql"
- name: "MYSQL_DATABASE"
value: "sample"
- name: "MYSQL_ROOT_PASSWORD"
value: "root"
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-persistent-storage
persistentVolumeClaim:
claimName: {{.pvcName}}`
}
func getBlockPodDefinition() string {
return `apiVersion: v1
kind: Pod
metadata:
name: {{.podName}}
spec:
containers:
- image: busybox
name: {{.podName}}
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
volumeMounts:
- name: block-persistent-storage
mountPath: ` + utils.TestMountPath + `
volumes:
- name: block-persistent-storage
persistentVolumeClaim:
claimName: {{.pvcName}}
readOnly: {{.readOnly}}
restartPolicy: Never`
}
-116
View File
@@ -1,116 +0,0 @@
/*
Copyright 2016 The Rook Authors. All rights reserved.
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 longhaul
import (
"math/rand"
"strings"
"sync"
"testing"
"time"
"github.com/icrowley/fake"
"github.com/rook/rook/tests/framework/clients"
"github.com/rook/rook/tests/framework/installer"
"github.com/rook/rook/tests/framework/utils"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
func createObjectStoreAndUser(t func() *testing.T, kh *utils.K8sHelper, tc *clients.TestClient, namespace string, storeName string, userId string, userName string) *utils.S3Helper {
if !isObjectStorePresent(kh, namespace, storeName) {
tc.ObjectClient.Create(namespace, storeName, 3)
}
/*ou, err := tc.ObjectClient.ObjectGetUser(storeName, userId)
if err != nil || *ou.DisplayName != userName {
tc.ObjectClient.CreateUser(storeName, userId, userName)
}
conninfo, conninfoError := tc.ObjectClient.ObjectGetUser(storeName, userId)
require.Nil(t(), conninfoError)
s3endpoint, _ := kh.GetRGWServiceURL(storeName, namespace)
s3client := utils.CreateNewS3Helper(s3endpoint, *conninfo.AccessKey, *conninfo.SecretKey)
return s3client*/
// TODO: Implement object user crd
return nil
}
func isObjectStorePresent(kh *utils.K8sHelper, namespace string, storeName string) bool {
listOpts := metav1.ListOptions{LabelSelector: "app=rook-ceph-rgw"}
podList, err := kh.Clientset.CoreV1().Pods(namespace).List(listOpts)
if err == nil {
for _, pod := range podList.Items {
lables := pod.GetObjectMeta().GetLabels()
if lables["rook_object_store"] == storeName {
return true
}
}
}
return false
}
func performObjectStoreOperations(s3 *utils.S3Helper, bucketName string) {
var wg sync.WaitGroup
for i := 1; i <= installer.Env.LoadConcurrentRuns; i++ {
wg.Add(1)
go bucketOperations(s3, bucketName, &wg, installer.Env.LoadTime, installer.Env.LoadSize)
}
wg.Wait()
}
func bucketOperations(s3 *utils.S3Helper, bucketName string, wg *sync.WaitGroup, runtime int, loadSize string) {
defer wg.Done()
ds := 512000
switch strings.ToLower(loadSize) {
case "small":
ds = 524288 //.5M * 5 = 2.5M per thread
case "medium":
ds = 2097152 //2M * 5 = 10M per thread
case "large":
ds = 10485760 //10M * 5 = 50M per thread
default:
ds = 1048576 // 1M * 5 = 5M per thread
}
start := time.Now()
elapsed := time.Since(start).Seconds()
for elapsed < float64(runtime) {
key1 := fake.CharactersN(30)
key2 := fake.CharactersN(30)
key3 := fake.CharactersN(30)
key4 := fake.CharactersN(30)
s3.PutObjectInBucket(bucketName, fake.CharactersN(ds), key1, "plain/text")
s3.PutObjectInBucket(bucketName, fake.CharactersN(ds), key2, "plain/text")
s3.PutObjectInBucket(bucketName, fake.CharactersN(ds), key3, "plain/text")
s3.PutObjectInBucket(bucketName, fake.CharactersN(ds), key4, "plain/text")
s3.PutObjectInBucket(bucketName, fake.CharactersN(ds), key1, "plain/text")
s3.GetObjectInBucket(bucketName, key1)
s3.GetObjectInBucket(bucketName, key2)
s3.GetObjectInBucket(bucketName, key3)
s3.DeleteObjectInBucket(bucketName, key4)
elapsed = time.Since(start).Seconds()
}
}
func randomBool() bool {
return rand.Intn(2) == 0
}
-102
View File
@@ -1,102 +0,0 @@
/*
Copyright 2016 The Rook Authors. All rights reserved.
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 longhaul
import (
"strconv"
"sync"
"testing"
"github.com/rook/rook/tests/framework/clients"
"time"
"github.com/rook/rook/tests/framework/installer"
"github.com/rook/rook/tests/framework/utils"
"github.com/stretchr/testify/suite"
)
// Rook Block Storage longhaul test
// Start Rook and set up a storage class and pool.
// Start multiple MySql databases that are using rook provisioned block storage.
// First block volume is persistent(mounted once) all the other volumes are mounted and unmounted per test
// NOTE: This tests doesn't clean up the cluster or volume after the run, the tests is designed
// to reuse the same cluster and volume for multiple runs or over a period of time.
// It is recommended to run this test with -count test param (to repeat th test n number of times)
// along with --load_parallel_runs params(number of concurrent operations per test) and
//--load_volumes(number of volumes that are created per test
func TestBlockLongHaul(t *testing.T) {
suite.Run(t, new(BlockLongHaulSuite))
}
type BlockLongHaulSuite struct {
suite.Suite
kh *utils.K8sHelper
installer *installer.CephInstaller
namespace string
op installer.TestSuite
testClient *clients.TestClient
}
// Test set up - does the following in order
// create pool and storage class, create a PVC, Create a MySQL app/service that uses pvc
func (s *BlockLongHaulSuite) SetupSuite() {
s.namespace = "longhaul-ns"
s.op, s.kh, s.installer = StartLoadTestCluster(s.T, s.namespace)
s.testClient = clients.CreateTestClient(s.kh, s.installer.Manifests)
createStorageClassAndPool(s.T, s.testClient, s.kh, s.namespace, "rook-ceph-block", "rook-pool")
}
// create a n number ofPVC, Create a MySQL app/service that uses pvc
// The first PVC and mysql pod are persistent i.e. they are never deleted
// All other PVC and mounts are created and deleted/unmounted per test
func (s *BlockLongHaulSuite) TestBlockLonghaulRun() {
var wg sync.WaitGroup
wg.Add(installer.Env.LoadVolumeNumber)
for i := 1; i <= installer.Env.LoadVolumeNumber; i++ {
if i == 1 {
go BlockVolumeOperations(s, &wg, "rook-ceph-block", "mysqlapp-persist", "mysqldb", "mysql-persist-claim", false)
} else {
go BlockVolumeOperations(s, &wg, "rook-ceph-block", "mysqlapp-ephemeral-"+strconv.Itoa(i), "mysqldbeph"+strconv.Itoa(i), "mysql-ephemeral-claim"+strconv.Itoa(i), randomBool())
}
}
wg.Wait()
}
func BlockVolumeOperations(s *BlockLongHaulSuite, wg *sync.WaitGroup, storageClassName string, appName string, appLabel string, pvcName string, cleanup bool) {
defer wg.Done()
db := createPVCAndMountMysqlPod(s.T, s.kh, storageClassName, appName, appLabel, pvcName)
performBlockOperations(db)
if cleanup {
mySqlPodOperation(s.kh, storageClassName, appName, appLabel, pvcName, "delete")
s.kh.WaitUntilPodWithLabelDeleted(appLabel, "default")
}
db.CloseConnection()
db = nil
time.Sleep(10 * time.Second)
}
func (s *BlockLongHaulSuite) TearDownSuite() {
// clean up all ephemeral block storage, index 1 is persistent block storage which is going to be used among different test runs.
for i := 2; i <= installer.Env.LoadVolumeNumber; i++ {
mySqlPodOperation(s.kh, "rook-ceph-block", "mysqlapp-ephemeral-"+strconv.Itoa(i), "mysqldbeph"+strconv.Itoa(i), "mysql-ephemeral-claim"+strconv.Itoa(i), "delete")
}
s.kh = nil
s = nil
}
-103
View File
@@ -1,103 +0,0 @@
/*
Copyright 2016 The Rook Authors. All rights reserved.
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 longhaul
import (
"strconv"
"sync"
"testing"
"time"
"github.com/rook/rook/tests/framework/clients"
"github.com/rook/rook/tests/framework/installer"
"github.com/rook/rook/tests/framework/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
)
// Rook Block Storage fencing longhaul test
// Create a PVC, mount a pod with readOnly= false and write some data and unmount pod
// Then Mound n pods concurrently with readOnly=true and read data.
// NOTE: This tests doesn't clean up the cluster or volume after the run, the tests is designed
// to reuse the same cluster and volume for multiple runs or over a period of time.
// It is recommended to run this test with -count test param (to repeat th test n number of times)
// along with --load_parallel_runs params(number of concurrent operations per test)
func TestBlockWithFencingLongHaul(t *testing.T) {
suite.Run(t, new(BlockLongHaulSuiteWithFencing))
}
type BlockLongHaulSuiteWithFencing struct {
suite.Suite
kh *utils.K8sHelper
installer *installer.CephInstaller
testClient *clients.TestClient
namespace string
op installer.TestSuite
}
// Test set up - does the following in order
// create pool and storage class, Create a PVC and mount a pod with ReadOnly=false.
// Write some data to the pvc and unmount the pod
func (s *BlockLongHaulSuiteWithFencing) SetupSuite() {
s.namespace = "longhaul-ns"
s.op, s.kh, s.installer = StartLoadTestCluster(s.T, s.namespace)
s.testClient = clients.CreateTestClient(s.kh, s.installer.Manifests)
createStorageClassAndPool(s.T, s.testClient, s.kh, s.namespace, "rook-ceph-block", "rook-pool")
if _, err := s.kh.GetPVCStatus(defaultNamespace, "block-pv-one"); err != nil {
logger.Infof("Creating PVC and mounting it to pod with readOnly set to false")
err = s.testClient.BlockClient.CreatePvc("block-pv-one", "rook-ceph-block", "ReadWriteOnce", "1M")
require.Nil(s.T(), err)
mountUnmountPVCOnPod(s.kh, "block-rw", "block-pv-one", "false", "apply")
require.True(s.T(), s.kh.IsPodRunning("block-rw", defaultNamespace))
filename := "longhaul"
assert.Nil(s.T(), s.kh.WriteToPod(defaultNamespace, "block-rw", filename, "this is long running test"))
mountUnmountPVCOnPod(s.kh, "block-rw", "block-pv-one", "false", "delete")
require.True(s.T(), s.kh.IsPodTerminated("block-rw", defaultNamespace))
time.Sleep(5 * time.Second)
}
}
// Mount n number of pods on the same PVC created earlier with readOnly=True.
func (s *BlockLongHaulSuiteWithFencing) TestBlockWithFencingLonghaulRun() {
var wg sync.WaitGroup
wg.Add(installer.Env.LoadVolumeNumber)
for i := 1; i <= installer.Env.LoadVolumeNumber; i++ {
go blockVolumeFencingOperations(s, &wg, "block-read"+strconv.Itoa(i), "block-pv-one")
}
wg.Wait()
}
func blockVolumeFencingOperations(s *BlockLongHaulSuiteWithFencing, wg *sync.WaitGroup, podName string, pvcName string) {
defer wg.Done()
mountUnmountPVCOnPod(s.kh, podName, pvcName, "true", "apply")
require.True(s.T(), s.kh.IsPodRunning(podName, defaultNamespace))
message := "this is long running test"
require.Nil(s.T(), s.kh.ReadFromPod("default", podName, "longhaul", message))
mountUnmountPVCOnPod(s.kh, podName, pvcName, "true", "delete")
require.True(s.T(), s.kh.IsPodTerminated(podName, defaultNamespace))
}
func (s *BlockLongHaulSuiteWithFencing) TearDownSuite() {
s.kh = nil
s.testClient = nil
s = nil
}
-66
View File
@@ -1,66 +0,0 @@
/*
Copyright 2016 The Rook Authors. All rights reserved.
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 longhaul
import (
"math/rand"
"time"
"github.com/coreos/pkg/capnslog"
"github.com/rook/rook/tests/framework/utils"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// utility to install and prometheus and grafana to monitor rook cluster
var (
logger = capnslog.NewPackageLogger("github.com/rook/rook", "longhaul")
)
type ChaosHelper struct {
namespace string
kh *utils.K8sHelper
}
func NewChaosHelper(namespace string, kh *utils.K8sHelper) *ChaosHelper {
return &ChaosHelper{namespace: namespace, kh: kh}
}
func (h *ChaosHelper) Monkey() {
time.Sleep(5 * time.Minute)
for {
logger.Info("Attempt to kill a Random Pod in namespace %s", h.namespace)
listOpts := metav1.ListOptions{}
pods, err := h.kh.Clientset.CoreV1().Pods(h.namespace).List(listOpts)
if err != nil {
logger.Infof("Error getting list of pods ,err ->%v", err)
return
}
kp := pods.Items[rand.Intn(len(pods.Items)-1)]
logger.Info("Killing pod with Name= %s", kp.Name)
propagation := metav1.DeletePropagationForeground
delOptions := &metav1.DeleteOptions{PropagationPolicy: &propagation}
err = h.kh.Clientset.CoreV1().Pods(h.namespace).Delete(kp.Name, delOptions)
if err != nil {
logger.Infof("Cannot delete pod %s, err->%v", kp.Name, err)
continue
}
logger.Infof("pod %s deleted", kp.Name)
time.Sleep(5 * time.Minute)
}
}
-102
View File
@@ -1,102 +0,0 @@
/*
Copyright 2016 The Rook Authors. All rights reserved.
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 longhaul
import (
"strconv"
"sync"
"testing"
"github.com/rook/rook/tests/framework/clients"
"github.com/rook/rook/tests/framework/installer"
"github.com/rook/rook/tests/framework/utils"
"github.com/stretchr/testify/suite"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// Rook Object Store longhaul test
// Start Rook, create an object store and object user
// Create object store bucket and perform CURD operations.
// This Test creates 1 to n object stores - first object store is present throughout the run,
// but all other object stores are deleted after each run.
// NOTE: This tests doesn't clean up the cluster or volume after the run, the tests is designed
// to reuse the same cluster and volume for multiple runs or over a period of time.
// It is recommended to run this test with -count test param (to repeat th test n number of times)
// along with --load_parallel_runs params(number of concurrent operations per test) and
//--load_volumes(number of volumes that are created per test
func TestObjectLongHaul(t *testing.T) {
suite.Run(t, new(ObjectLongHaulSuite))
}
type ObjectLongHaulSuite struct {
suite.Suite
kh *utils.K8sHelper
installer *installer.CephInstaller
tc *clients.TestClient
namespace string
op installer.TestSuite
}
func (s *ObjectLongHaulSuite) SetupSuite() {
s.namespace = "longhaul-ns"
s.op, s.kh, s.installer = StartLoadTestCluster(s.T, s.namespace)
s.tc = clients.CreateTestClient(s.kh, s.installer.Manifests)
}
func (s *ObjectLongHaulSuite) TestObjectLonghaulRun() {
var wg sync.WaitGroup
storeName := "longhaulstore"
wg.Add(installer.Env.LoadVolumeNumber)
for i := 1; i <= installer.Env.LoadVolumeNumber; i++ {
if i == 1 {
go ObjectStoreOperations(s, &wg, s.namespace, storeName+strconv.Itoa(i), false)
} else {
go ObjectStoreOperations(s, &wg, s.namespace, storeName+strconv.Itoa(i), randomBool())
}
}
wg.Wait()
}
func ObjectStoreOperations(s *ObjectLongHaulSuite, wg *sync.WaitGroup, namespace string, storeName string, deleteStore bool) {
defer wg.Done()
bucketName := "loadbucket"
s3 := createObjectStoreAndUser(s.T, s.kh, s.tc, s.namespace, storeName, "longhaul", "LongHaulTest")
isFound, err := s3.IsBucketPresent(bucketName)
if err == nil {
if !isFound {
s3.CreateBucket(bucketName)
}
} else {
logger.Infof("Error which check if %s bucket exists, err -> %v", bucketName, err)
s.T().Fail()
}
performObjectStoreOperations(s3, bucketName)
if deleteStore {
delOpts := metav1.DeleteOptions{}
s.tc.ObjectClient.Delete(namespace, storeName)
s.kh.Clientset.CoreV1().Services(namespace).Delete("rgw-external-"+storeName, &delOpts)
}
s3 = nil
}
func (s *ObjectLongHaulSuite) TearDownSuite() {
s.tc = nil
s.kh = nil
s = nil
}