diff --git a/.travis.yml b/.travis.yml index 2e9ac2d6..4ab8b1de 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ sudo: required -dist: xenial +dist: bionic env: global: - CHANGE_MINIKUBE_NONE_USER=true @@ -46,7 +46,7 @@ install: before_script: - "./buildscripts/travis-build.sh" script: - - make ci + - sudo -E env "PATH=$PATH" make ci after_success: - make deploy-images - bash <(curl -s https://codecov.io/bash) diff --git a/ci/ci-test.sh b/ci/ci-test.sh index ab9875fe..fa414802 100755 --- a/ci/ci-test.sh +++ b/ci/ci-test.sh @@ -63,6 +63,8 @@ sudo zpool status sudo zfs list -t all +sudo zfs get all + echo "******************** ZFS Controller logs***************************** " dumpControllerLogs 1000 diff --git a/pkg/mgmt/mgmt.go b/pkg/mgmt/mgmt.go index 20dcee42..cf252f8f 100644 --- a/pkg/mgmt/mgmt.go +++ b/pkg/mgmt/mgmt.go @@ -89,7 +89,7 @@ func (c *ZVController) syncZV(zv *apis.ZFSVolume) error { // the volume. And if it is set then volume has already been // created and this event is for property change only. if zv.Finalizers != nil { - err = zfs.SetZvolProp(zv) + err = zfs.SetVolumeProp(zv) } else { err = zfs.CreateVolume(zv) if err == nil { diff --git a/pkg/zfs/zfs_util.go b/pkg/zfs/zfs_util.go index cb42edcf..e1a81060 100644 --- a/pkg/zfs/zfs_util.go +++ b/pkg/zfs/zfs_util.go @@ -36,6 +36,7 @@ const ( ZFSCreateArg = "create" ZFSDestroyArg = "destroy" ZFSSetArg = "set" + ZFSGetArg = "get" ZFSListArg = "list" ) @@ -270,8 +271,26 @@ func UmountZFSDataset(vol *apis.ZFSVolume) error { return SetDatasetMountProp(volume, "none") } -// SetZvolProp sets the volume property -func SetZvolProp(vol *apis.ZFSVolume) error { +// GetVolumeProperty gets zfs properties for the volume +func GetVolumeProperty(vol *apis.ZFSVolume, prop string) (string, error) { + var ZFSVolArg []string + volume := vol.Spec.PoolName + "/" + vol.Name + + ZFSVolArg = append(ZFSVolArg, ZFSGetArg, "-pH", "-o", "value", prop, volume) + + cmd := exec.Command(ZFSVolCmd, ZFSVolArg...) + out, err := cmd.CombinedOutput() + if err != nil { + logrus.Errorf("zfs: could not get %s on dataset %v cmd %v error: %s", + prop, volume, ZFSVolArg, string(out)) + return "", err + } + val := out[:len(out)-1] + return string(val), nil +} + +// SetVolumeProp sets the volume property +func SetVolumeProp(vol *apis.ZFSVolume) error { var err error volume := vol.Spec.PoolName + "/" + vol.Name diff --git a/tests/provision_test.go b/tests/provision_test.go index 5e021f13..8be906fd 100644 --- a/tests/provision_test.go +++ b/tests/provision_test.go @@ -31,6 +31,7 @@ func datasetCreationTest() { By("creating and verifying PVC bound status", createAndVerifyPVC) By("Creating and deploying app pod", createDeployVerifyApp) By("verifying ZFSVolume object", VerifyZFSVolume) + By("verifying ZFSVolume property change", VerifyZFSVolumePropEdit) By("Deleting application deployment", deleteAppDeployment) By("Deleting pvc", deletePVC) By("Deleting storage class", deleteStorageClass) @@ -49,6 +50,7 @@ func zvolCreationTest() { */ //By("Creating and deploying app pod", createDeployVerifyApp) By("verifying ZFSVolume object", VerifyZFSVolume) + By("verifying ZFSVolume property change", VerifyZFSVolumePropEdit) //By("Deleting application deployment", deleteAppDeployment) By("Deleting pvc", deletePVC) By("Deleting storage class", deleteStorageClass) diff --git a/tests/suite_test.go b/tests/suite_test.go index 25361cd7..c01f201b 100644 --- a/tests/suite_test.go +++ b/tests/suite_test.go @@ -17,6 +17,7 @@ limitations under the License. package tests import ( + "github.com/Sirupsen/logrus" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/openebs/zfs-localpv/pkg/builder" @@ -40,31 +41,35 @@ const ( ) var ( - ZFSClient *builder.Kubeclient - SCClient *sc.Kubeclient - PVCClient *pvc.Kubeclient - DeployClient *deploy.Kubeclient - PodClient *pod.KubeClient - openebsNamespace = "openebs" - nsName = "zfspv-provision" - scName = "zfspv-sc" - ZFSProvisioner = "zfs.csi.openebs.io" - pvcName = "zfspv-pvc" - appName = "busybox-zfspv" + ZFSClient *builder.Kubeclient + SCClient *sc.Kubeclient + PVCClient *pvc.Kubeclient + DeployClient *deploy.Kubeclient + PodClient *pod.KubeClient + nsName = "zfspv-provision" + scName = "zfspv-sc" + ZFSProvisioner = "zfs.csi.openebs.io" + pvcName = "zfspv-pvc" + appName = "busybox-zfspv" - nsObj *corev1.Namespace - scObj *storagev1.StorageClass - deployObj *appsv1.Deployment - pvcObj *corev1.PersistentVolumeClaim - appPod *corev1.PodList - accessModes = []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce} - capacity = "5368709120" // 5Gi - KubeConfigPath string + nsObj *corev1.Namespace + scObj *storagev1.StorageClass + deployObj *appsv1.Deployment + pvcObj *corev1.PersistentVolumeClaim + appPod *corev1.PodList + accessModes = []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce} + capacity = "5368709120" // 5Gi + KubeConfigPath string + OpenEBSNamespace string ) func init() { KubeConfigPath = os.Getenv("KUBECONFIG") + OpenEBSNamespace = os.Getenv("OPENEBS_NAMESPACE") + if OpenEBSNamespace == "" { + logrus.Fatalf("OPENEBS_NAMESPACE environment variable not set") + } SCClient = sc.NewKubeClient(sc.WithKubeConfigPath(KubeConfigPath)) PVCClient = pvc.NewKubeClient(pvc.WithKubeConfigPath(KubeConfigPath)) DeployClient = deploy.NewKubeClient(deploy.WithKubeConfigPath(KubeConfigPath)) diff --git a/tests/utils.go b/tests/utils.go index eff926e2..2101cc4b 100644 --- a/tests/utils.go +++ b/tests/utils.go @@ -21,6 +21,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + apis "github.com/openebs/zfs-localpv/pkg/apis/openebs.io/core/v1alpha1" "github.com/openebs/zfs-localpv/pkg/zfs" "github.com/openebs/zfs-localpv/tests/container" "github.com/openebs/zfs-localpv/tests/deploy" @@ -42,7 +43,7 @@ func IsPVCBoundEventually(pvcName string) bool { Expect(err).ShouldNot(HaveOccurred()) return pvc.NewForAPIObject(volume).IsBound() }, - 120, 10). + 60, 5). Should(BeTrue()) } @@ -56,7 +57,19 @@ func IsPodRunningEventually(namespace, podName string) bool { return pod.NewForAPIObject(p). IsRunning() }, - 150, 10). + 60, 5). + Should(BeTrue()) +} + +// IsPropUpdatedEventually checks if the property is updated or not eventually +func IsPropUpdatedEventually(vol *apis.ZFSVolume, prop string, val string) bool { + return Eventually(func() bool { + + newVal, err := zfs.GetVolumeProperty(vol, prop) + Expect(err).ShouldNot(HaveOccurred()) + return (newVal == val) + }, + 60, 5). Should(BeTrue()) } @@ -119,7 +132,7 @@ func createZfsStorageClass() { func VerifyZFSVolume() { By("fetching zfs volume") - vol, err := ZFSClient.WithNamespace(openebsNamespace). + vol, err := ZFSClient.WithNamespace(OpenEBSNamespace). Get(pvcObj.Spec.VolumeName, metav1.GetOptions{}) Expect(err).To(BeNil(), "while fetching the zfs volume {%s}", pvcObj.Spec.VolumeName) @@ -142,6 +155,104 @@ func VerifyZFSVolume() { Expect(vol.Finalizers[0]).To(Equal(zfs.ZFSFinalizer), "while checking finializer to be set {%s}", pvcObj.Spec.VolumeName) } +func VerifyZFSVolumePropEdit() { + By("verifying compression property update") + + By("fetching zfs volume for setting compression=on") + vol, err := ZFSClient.WithNamespace(OpenEBSNamespace). + Get(pvcObj.Spec.VolumeName, metav1.GetOptions{}) + Expect(err).To(BeNil(), "while fetching the zfs volume {%s}", vol.Name) + + val := "on" + vol.Spec.Compression = val + _, err = ZFSClient.WithNamespace(OpenEBSNamespace).Update(vol) + Expect(err).To(BeNil(), "while updating the zfs volume {%s}", vol.Name) + + status := IsPropUpdatedEventually(vol, "compression", val) + Expect(status).To(Equal(true), "while updating compression=on {%s}", vol.Name) + + By("fetching zfs volume for setting compression=off") + vol, err = ZFSClient.WithNamespace(OpenEBSNamespace). + Get(pvcObj.Spec.VolumeName, metav1.GetOptions{}) + Expect(err).To(BeNil(), "while fetching the zfs volume {%s}", vol.Name) + + val = "off" + vol.Spec.Compression = val + _, err = ZFSClient.WithNamespace(OpenEBSNamespace).Update(vol) + Expect(err).To(BeNil(), "while updating the zfs volume {%s}", vol.Name) + + status = IsPropUpdatedEventually(vol, "compression", val) + Expect(status).To(Equal(true), "while updating compression=off {%s}", vol.Name) + + By("verifying dedup property update") + + By("fetching zfs volume for setting dedup=on") + vol, err = ZFSClient.WithNamespace(OpenEBSNamespace). + Get(pvcObj.Spec.VolumeName, metav1.GetOptions{}) + Expect(err).To(BeNil(), "while fetching the zfs volume {%s}", vol.Name) + + val = "on" + vol.Spec.Dedup = val + _, err = ZFSClient.WithNamespace(OpenEBSNamespace).Update(vol) + Expect(err).To(BeNil(), "while updating the zfs volume {%s}", vol.Name) + + status = IsPropUpdatedEventually(vol, "dedup", val) + Expect(status).To(Equal(true), "while updating dedup=on {%s}", vol.Name) + + By("fetching zfs volume for setting dedup=off") + vol, err = ZFSClient.WithNamespace(OpenEBSNamespace). + Get(pvcObj.Spec.VolumeName, metav1.GetOptions{}) + Expect(err).To(BeNil(), "while fetching the zfs volume {%s}", vol.Name) + + val = "off" + vol.Spec.Dedup = val + _, err = ZFSClient.WithNamespace(OpenEBSNamespace).Update(vol) + Expect(err).To(BeNil(), "while updating the zfs volume {%s}", vol.Name) + + status = IsPropUpdatedEventually(vol, "dedup", val) + Expect(status).To(Equal(true), "while updating dedup=off {%s}", vol.Name) + + if vol.Spec.VolumeType == zfs.VOLTYPE_DATASET { + By("verifying recordsize property update") + + By("fetching zfs volume for setting the recordsize") + vol, err = ZFSClient.WithNamespace(OpenEBSNamespace). + Get(pvcObj.Spec.VolumeName, metav1.GetOptions{}) + Expect(err).To(BeNil(), "while fetching the zfs volume {%s}", vol.Name) + + val = "4096" // 4k + vol.Spec.RecordSize = val + vol.Spec.VolBlockSize = "8192" + _, err = ZFSClient.WithNamespace(OpenEBSNamespace).Update(vol) + Expect(err).To(BeNil(), "while updating the zfs volume {%s}", vol.Name) + + status = IsPropUpdatedEventually(vol, "recordsize", val) + Expect(status).To(Equal(true), "while updating redordsize {%s}", vol.Name) + } else { + + Expect(vol.Spec.VolumeType).To(Equal(zfs.VOLTYPE_ZVOL), "voltype should be zvol {%s}", vol.Name) + + By("verifying blocksize property update") + + By("fetching zfs volume for setting the blocksize") + vol, err = ZFSClient.WithNamespace(OpenEBSNamespace). + Get(pvcObj.Spec.VolumeName, metav1.GetOptions{}) + Expect(err).To(BeNil(), "while fetching the zfs volume {%s}", vol.Name) + + val, err = zfs.GetVolumeProperty(vol, "volblocksize") + Expect(err).ShouldNot(HaveOccurred()) + + nval := "8192" // 8k + vol.Spec.VolBlockSize = nval + vol.Spec.RecordSize = "16384" + _, err = ZFSClient.WithNamespace(OpenEBSNamespace).Update(vol) + Expect(err).To(BeNil(), "while updating the zfs volume {%s}", vol.Name) + + status = IsPropUpdatedEventually(vol, "volblocksize", val) + Expect(status).To(Equal(true), "while updating volblocksize {%s}", vol.Name) + } +} + func deleteStorageClass() { err := SCClient.Delete(scObj.Name, &metav1.DeleteOptions{}) Expect(err).To(BeNil(), @@ -156,7 +267,7 @@ func createAndVerifyPVC() { By("building a pvc") pvcObj, err = pvc.NewBuilder(). WithName(pvcName). - WithNamespace(openebsNamespace). + WithNamespace(OpenEBSNamespace). WithStorageClass(scObj.Name). WithAccessModes(accessModes). WithCapacity(capacity).Build() @@ -164,16 +275,16 @@ func createAndVerifyPVC() { HaveOccurred(), "while building pvc {%s} in namespace {%s}", pvcName, - openebsNamespace, + OpenEBSNamespace, ) By("creating above pvc") - pvcObj, err = PVCClient.WithNamespace(openebsNamespace).Create(pvcObj) + pvcObj, err = PVCClient.WithNamespace(OpenEBSNamespace).Create(pvcObj) Expect(err).To( BeNil(), "while creating pvc {%s} in namespace {%s}", pvcName, - openebsNamespace, + OpenEBSNamespace, ) By("verifying pvc status as bound") @@ -182,12 +293,12 @@ func createAndVerifyPVC() { Expect(status).To(Equal(true), "while checking status equal to bound") - pvcObj, err = PVCClient.WithNamespace(openebsNamespace).Get(pvcObj.Name, metav1.GetOptions{}) + pvcObj, err = PVCClient.WithNamespace(OpenEBSNamespace).Get(pvcObj.Name, metav1.GetOptions{}) Expect(err).To( BeNil(), "while retrieving pvc {%s} in namespace {%s}", pvcName, - openebsNamespace, + OpenEBSNamespace, ) } @@ -202,7 +313,7 @@ func createAndDeployAppPod() { By("building a busybox app pod deployment using above zfs volume") deployObj, err = deploy.NewBuilder(). WithName(appName). - WithNamespace(openebsNamespace). + WithNamespace(OpenEBSNamespace). WithLabelsNew( map[string]string{ "app": "busybox", @@ -251,41 +362,41 @@ func createAndDeployAppPod() { Expect(err).ShouldNot(HaveOccurred(), "while building app deployement {%s}", appName) - deployObj, err = DeployClient.WithNamespace(openebsNamespace).Create(deployObj) + deployObj, err = DeployClient.WithNamespace(OpenEBSNamespace).Create(deployObj) Expect(err).ShouldNot( HaveOccurred(), "while creating pod {%s} in namespace {%s}", appName, - openebsNamespace, + OpenEBSNamespace, ) } func verifyAppPodRunning() { var err error - appPod, err = PodClient.WithNamespace(openebsNamespace). + appPod, err = PodClient.WithNamespace(OpenEBSNamespace). List(metav1.ListOptions{ LabelSelector: "app=busybox", }, ) Expect(err).ShouldNot(HaveOccurred(), "while verifying application pod") - status := IsPodRunningEventually(openebsNamespace, appPod.Items[0].Name) + status := IsPodRunningEventually(OpenEBSNamespace, appPod.Items[0].Name) Expect(status).To(Equal(true), "while checking status of pod {%s}", appPod.Items[0].Name) } func deleteAppDeployment() { - err := DeployClient.WithNamespace(openebsNamespace). + err := DeployClient.WithNamespace(OpenEBSNamespace). Delete(deployObj.Name, &metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred(), "while deleting application pod") } func deletePVC() { - err := PVCClient.WithNamespace(openebsNamespace).Delete(pvcName, &metav1.DeleteOptions{}) + err := PVCClient.WithNamespace(OpenEBSNamespace).Delete(pvcName, &metav1.DeleteOptions{}) Expect(err).To( BeNil(), "while deleting pvc {%s} in namespace {%s}", pvcName, - openebsNamespace, + OpenEBSNamespace, ) By("verifying deleted pvc") status := IsPVCDeletedEventually(pvcName)