package tests_test import ( "context" "fmt" "strconv" "strings" "time" . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/extensions/table" . "github.com/onsi/gomega" "github.com/coreos/go-semver/semver" route1client "github.com/openshift/client-go/route/clientset/versioned" extensionsv1beta1 "k8s.io/api/extensions/v1beta1" storagev1 "k8s.io/api/storage/v1" apiequality "k8s.io/apimachinery/pkg/api/equality" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/client-go/tools/clientcmd" cdiv1 "kubevirt.io/containerized-data-importer/pkg/apis/core/v1beta1" "kubevirt.io/containerized-data-importer/pkg/common" "kubevirt.io/containerized-data-importer/pkg/controller" "kubevirt.io/containerized-data-importer/tests" "kubevirt.io/containerized-data-importer/tests/framework" "kubevirt.io/containerized-data-importer/tests/utils" ) const ( ingressUrl = "www.super-duper-test.ingress.tt.org" routeName = "cdi-uploadproxy" ) var ( defaultUrl = "" ) var _ = Describe("CDI storage class config tests", func() { var ( f = framework.NewFramework("cdiconfig-test") defaultSc, secondSc *storagev1.StorageClass origSpec *cdiv1.CDIConfigSpec ) BeforeEach(func() { storageClasses, err := f.K8sClient.StorageV1().StorageClasses().List(context.TODO(), metav1.ListOptions{}) Expect(err).ToNot(HaveOccurred()) for _, sc := range storageClasses.Items { if defaultClassValue, ok := sc.Annotations[controller.AnnDefaultStorageClass]; ok { if defaultClassValue == "true" { defaultSc = &sc break } } } config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) origSpec = config.Spec.DeepCopy() By("Unsetting storage class override if set.") err = utils.UpdateCDIConfig(f.CrClient, func(config *cdiv1.CDIConfigSpec) { config.ScratchSpaceStorageClass = nil }) Expect(err).ToNot(HaveOccurred()) By("Waiting for default SC to be the default scratch space storage class") Eventually(func() string { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) return config.Status.ScratchSpaceStorageClass }, time.Second*30, time.Second).Should(Equal(defaultSc.Name)) }) AfterEach(func() { if secondSc != nil { By("Unmarking default " + secondSc.Name) err := SetStorageClassDefault(f, secondSc.Name, false) Expect(err).ToNot(HaveOccurred()) secondSc = nil } if defaultSc != nil { By("Restoring default to " + defaultSc.Name) err := SetStorageClassDefault(f, defaultSc.Name, true) Expect(err).ToNot(HaveOccurred()) defaultSc = nil } By("Restoring CDIConfig to original state") err := utils.UpdateCDIConfig(f.CrClient, func(config *cdiv1.CDIConfigSpec) { origSpec.DeepCopyInto(config) }) Expect(err).ToNot(HaveOccurred()) Eventually(func() bool { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) return apiequality.Semantic.DeepEqual(config.Spec, *origSpec) }, timeout, pollingInterval).Should(BeTrue(), "CDIConfig not properly restored to original value") Eventually(func() bool { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) return !apiequality.Semantic.DeepEqual(config.Status, cdiv1.CDIConfigStatus{}) }, timeout, pollingInterval).Should(BeTrue(), "CDIConfig status not restored by config controller") }) It("[test_id:3962]should have the default storage class as its scratchSpaceStorageClass", func() { if defaultSc == nil { Skip("No default storage class found, skipping test") } By("Expecting default storage class to be: " + defaultSc.Name) config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) Expect(config.Status.ScratchSpaceStorageClass).To(Equal(defaultSc.Name)) }) It("[test_id:3964]should set the scratch space to blank if no default exists", func() { if defaultSc == nil { Skip("No default storage class found, skipping test") } By("Expecting default storage class to be " + defaultSc.Name) config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) Expect(defaultSc.Name).To(Equal(config.Status.ScratchSpaceStorageClass)) err = SetStorageClassDefault(f, defaultSc.Name, false) Expect(err).ToNot(HaveOccurred()) By("Expecting default storage class to be blank") Eventually(func() string { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) return config.Status.ScratchSpaceStorageClass }, time.Second*30, time.Second).Should(Equal("")) }) It("[test_id:3965]should keep the default if you specify an invalid override", func() { if defaultSc == nil { Skip("No default storage class found, skipping test") } By("Expecting default storage class to be " + defaultSc.Name) invalid := "invalidsc" err := utils.UpdateCDIConfig(f.CrClient, func(config *cdiv1.CDIConfigSpec) { config.ScratchSpaceStorageClass = &invalid }) Expect(err).ToNot(HaveOccurred()) Eventually(func() string { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) if config.Spec.ScratchSpaceStorageClass == nil { return "" } return *config.Spec.ScratchSpaceStorageClass }, time.Second*30, time.Second).Should(Equal(invalid)) config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) Expect(defaultSc.Name).To(Equal(config.Status.ScratchSpaceStorageClass)) }) It("[test_id:3966]Should react to switching the default storage class", func() { storageClasses, err := f.K8sClient.StorageV1().StorageClasses().List(context.TODO(), metav1.ListOptions{}) Expect(err).ToNot(HaveOccurred()) if len(storageClasses.Items) < 2 { Skip("Not enough storage classes to switch default") } By("Expecting default storage class to be " + defaultSc.Name) config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) Expect(defaultSc.Name).To(Equal(config.Status.ScratchSpaceStorageClass)) By("Switching default sc") err = SetStorageClassDefault(f, defaultSc.Name, false) Expect(err).ToNot(HaveOccurred()) for _, sc := range storageClasses.Items { if sc.Name != defaultSc.Name { // Found other class, now set it to default. secondSc = &sc err = SetStorageClassDefault(f, sc.Name, true) Expect(err).ToNot(HaveOccurred()) break } } By("Expecting default storage class to be " + secondSc.Name) Eventually(func() string { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) return config.Status.ScratchSpaceStorageClass }, time.Second*30, time.Second).Should(Equal(secondSc.Name)) }) It("[test_id:3967]Should use the override even if a different default is set", func() { storageClasses, err := f.K8sClient.StorageV1().StorageClasses().List(context.TODO(), metav1.ListOptions{}) Expect(err).ToNot(HaveOccurred()) if len(storageClasses.Items) < 2 { Skip("Not enough storage classes to test overrider") } config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) // Make sure default is current value. Expect(defaultSc.Name).To(Equal(config.Status.ScratchSpaceStorageClass)) var override string for _, sc := range storageClasses.Items { if sc.Name != defaultSc.Name { // Found other class, now set it to default. override = sc.Name break } } err = utils.UpdateCDIConfig(f.CrClient, func(config *cdiv1.CDIConfigSpec) { config.ScratchSpaceStorageClass = &override }) Expect(err).ToNot(HaveOccurred()) By("Verifying the override " + override + " is now the scratchspace name") Eventually(func() string { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) return config.Status.ScratchSpaceStorageClass }, time.Second*30, time.Second).Should(Equal(override)) }) }) var _ = Describe("CDI ingress config tests, using manifests", func() { var ( f = framework.NewFramework("cdiconfig-test") routeStart = func() string { return fmt.Sprintf("%s-%s.", routeName, f.CdiInstallNs) } manifestFile string ) BeforeEach(func() { version := *semver.New(tests.GetKubeVersion(f)) minVersion := *semver.New("1.14.0") if version.LessThan(minVersion) { Skip(fmt.Sprintf("kubernetes version %s, doesn't support network ingress", version.String())) } cfg, err := clientcmd.BuildConfigFromFlags(f.Master, f.KubeConfig) Expect(err).ToNot(HaveOccurred()) By("Checking if a route exists, we set that as default") openshiftClient, err := route1client.NewForConfig(cfg) Expect(err).ToNot(HaveOccurred()) _, err = openshiftClient.RouteV1().Routes(f.CdiInstallNs).Get(context.TODO(), "cdi-uploadproxy", metav1.GetOptions{}) if err == nil { By("setting defaultURL to route") Eventually(func() bool { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) if config.Status.UploadProxyURL == nil { return false } return strings.HasPrefix(*config.Status.UploadProxyURL, routeStart()) }, time.Second*30, time.Second).Should(BeTrue()) config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) defaultUrl = *config.Status.UploadProxyURL } By("Making sure no url is set") Eventually(func() string { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) if config.Status.UploadProxyURL == nil { return "" } return *config.Status.UploadProxyURL }, time.Second*30, time.Second).Should(Equal(defaultUrl)) }) AfterEach(func() { tests.RunKubectlCommand(f, "delete", "-f", manifestFile, "-n", f.CdiInstallNs) Eventually(func() string { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) if config.Status.UploadProxyURL == nil { return "" } return *config.Status.UploadProxyURL }, time.Second*30, time.Second).Should(Equal(defaultUrl)) }) It("[test_id:4949]Should properly react to network ingress", func() { manifestFile = "manifests/ingressNetworkApigroup.yaml" out, err := tests.RunKubectlCommand(f, "create", "-f", manifestFile, "-n", f.CdiInstallNs) fmt.Fprintf(GinkgoWriter, "INFO: Output from kubectl: %s\n", out) Expect(err).ToNot(HaveOccurred()) Eventually(func() string { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) if config.Status.UploadProxyURL != nil { return *config.Status.UploadProxyURL } return "" }, time.Second*30, time.Second).Should(Equal("test.manifest.example.com")) }) It("[test_id:4950]Keep current value on no http rule ingress", func() { manifestFile = "manifests/ingressNoHttp.yaml" controllerPod, err := utils.FindPodByPrefix(f.K8sClient, f.CdiInstallNs, cdiDeploymentPodPrefix, "app=containerized-data-importer") Expect(err).ToNot(HaveOccurred()) currentRestarts := controllerPod.Status.ContainerStatuses[0].RestartCount fmt.Fprintf(GinkgoWriter, "INFO: Current number of restarts: %d\n", currentRestarts) out, err := tests.RunKubectlCommand(f, "create", "-f", manifestFile, "-n", f.CdiInstallNs) fmt.Fprintf(GinkgoWriter, "INFO: Output from kubectl: %s\n", out) Expect(err).ToNot(HaveOccurred()) Eventually(func() string { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) if config.Status.UploadProxyURL != nil { return *config.Status.UploadProxyURL } return "" }, time.Second*30, time.Second).Should(Equal(defaultUrl)) for i := 0; i < 10; i++ { // Check for 20 seconds if the deployment pod crashed. time.Sleep(2 * time.Second) controllerPod, err = utils.FindPodByPrefix(f.K8sClient, f.CdiInstallNs, cdiDeploymentPodPrefix, "app=containerized-data-importer") Expect(err).ToNot(HaveOccurred()) // Restarts will increase if we crashed due to null pointer. Expect(currentRestarts).To(Equal(controllerPod.Status.ContainerStatuses[0].RestartCount)) } }) }) var _ = Describe("CDI ingress config tests", func() { var ( f = framework.NewFramework("cdiconfig-test") routeStart = func() string { return fmt.Sprintf("%s-%s.", routeName, f.CdiInstallNs) } ingress *extensionsv1beta1.Ingress ) BeforeEach(func() { cfg, err := clientcmd.BuildConfigFromFlags(f.Master, f.KubeConfig) Expect(err).ToNot(HaveOccurred()) By("Checking if a route exists, we set that as default") openshiftClient, err := route1client.NewForConfig(cfg) Expect(err).ToNot(HaveOccurred()) _, err = openshiftClient.RouteV1().Routes(f.CdiInstallNs).Get(context.TODO(), "cdi-uploadproxy", metav1.GetOptions{}) if err == nil { By("setting defaultURL to route") Eventually(func() bool { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) if config.Status.UploadProxyURL == nil { return false } return strings.HasPrefix(*config.Status.UploadProxyURL, routeStart()) }, time.Second*30, time.Second).Should(BeTrue()) config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) defaultUrl = *config.Status.UploadProxyURL } By("Making sure no url is set") Eventually(func() string { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) if config.Status.UploadProxyURL == nil { return "" } return *config.Status.UploadProxyURL }, time.Second*30, time.Second).Should(Equal(defaultUrl)) }) AfterEach(func() { By("Unsetting override") err := utils.UpdateCDIConfig(f.CrClient, func(config *cdiv1.CDIConfigSpec) { config.UploadProxyURLOverride = nil }) Expect(err).ToNot(HaveOccurred()) if ingress != nil { By("Cleaning up ingress") err := f.K8sClient.ExtensionsV1beta1().Ingresses(ingress.Namespace).Delete(context.TODO(), ingress.Name, metav1.DeleteOptions{}) Expect(err).ToNot(HaveOccurred()) Eventually(func() string { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) if config.Status.UploadProxyURL == nil { return "" } return *config.Status.UploadProxyURL }, time.Second*30, time.Second).Should(Equal(defaultUrl)) } }) It("[test_id:3960]Should set uploadProxyURL if override is not defined", func() { // TODO, don't hard code "cdi-uploadproxy", read it from container env of cdi-deployment deployment. ingress = createIngress("test-ingress", f.CdiInstallNs, "cdi-uploadproxy", ingressUrl) _, err := f.K8sClient.ExtensionsV1beta1().Ingresses(f.CdiInstallNs).Create(context.TODO(), ingress, metav1.CreateOptions{}) Expect(err).ToNot(HaveOccurred()) By("Expecting uploadproxy url to be " + ingressUrl) Eventually(func() string { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) if config.Status.UploadProxyURL == nil { return "" } return *config.Status.UploadProxyURL }, time.Second*30, time.Second).Should(Equal(ingressUrl)) }) It("[test_id:3961]Should keep override uploadProxyURL if override is defined", func() { override := "www.override.tt.org" err := utils.UpdateCDIConfig(f.CrClient, func(config *cdiv1.CDIConfigSpec) { config.UploadProxyURLOverride = &override }) Expect(err).ToNot(HaveOccurred()) // TODO, don't hard code "cdi-uploadproxy", read it from container env of cdi-deployment deployment. ingress = createIngress("test-ingress", f.CdiInstallNs, "cdi-uploadproxy", ingressUrl) _, err = f.K8sClient.ExtensionsV1beta1().Ingresses(f.CdiInstallNs).Create(context.TODO(), ingress, metav1.CreateOptions{}) Expect(err).ToNot(HaveOccurred()) By("Expecting uploadproxy url to be " + override) Eventually(func() string { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) if config.Status.UploadProxyURL == nil { return "" } return *config.Status.UploadProxyURL }, time.Second*30, time.Second).Should(Equal(override)) }) }) var _ = Describe("CDI route config tests", func() { var ( f = framework.NewFramework("cdiconfig-test") routeStart = func() string { return fmt.Sprintf("%s-%s.", routeName, f.CdiInstallNs) } openshiftClient *route1client.Clientset ) BeforeEach(func() { cfg, err := clientcmd.BuildConfigFromFlags(f.Master, f.KubeConfig) Expect(err).ToNot(HaveOccurred()) openshiftClient, err = route1client.NewForConfig(cfg) Expect(err).ToNot(HaveOccurred()) _, err = openshiftClient.RouteV1().Routes(f.CdiInstallNs).Get(context.TODO(), "cdi-uploadproxy", metav1.GetOptions{}) if err != nil { Skip("Unable to list routes, skipping") } By("Making sure no url is set to default route") Eventually(func() bool { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) if config.Status.UploadProxyURL == nil { return false } return strings.HasPrefix(*config.Status.UploadProxyURL, routeStart()) }, time.Second*30, time.Second).Should(BeTrue()) }) AfterEach(func() { By("Unsetting override") err := utils.UpdateCDIConfig(f.CrClient, func(config *cdiv1.CDIConfigSpec) { config.UploadProxyURLOverride = nil }) Expect(err).ToNot(HaveOccurred()) }) It("[test_id:4951]Should override uploadProxyURL if override is set", func() { if openshiftClient == nil { Skip("Routes not available") } override := "www.override.tt.org" err := utils.UpdateCDIConfig(f.CrClient, func(config *cdiv1.CDIConfigSpec) { config.UploadProxyURLOverride = &override }) Expect(err).ToNot(HaveOccurred()) Eventually(func() string { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) if config.Status.UploadProxyURL == nil { return "" } return *config.Status.UploadProxyURL }, time.Second*30, time.Second).Should(Equal(override)) }) }) var _ = Describe("CDIConfig instance management", func() { f := framework.NewFramework("cdiconfig-test") It("[test_id:4952]Should re-create the object if deleted", func() { By("Verifying the object exists") config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) // Save the UID, so we can check it against a new one. orgUID := config.GetUID() GinkgoWriter.Write([]byte(fmt.Sprintf("Original CDIConfig UID: %s\n", orgUID))) By("Deleting the object") err = f.CdiClient.CdiV1beta1().CDIConfigs().Delete(context.TODO(), config.Name, metav1.DeleteOptions{}) Expect(err).ToNot(HaveOccurred()) Eventually(func() bool { newConfig, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) if err != nil { return false } GinkgoWriter.Write([]byte(fmt.Sprintf("New CDIConfig UID: %s\n", newConfig.GetUID()))) return orgUID != newConfig.GetUID() }, time.Second*30, time.Second).Should(BeTrue()) }) }) var _ = Describe("Modifying CDIConfig spec tests", func() { var origSpec *cdiv1.CDIConfigSpec f := framework.NewFramework("cdiconfig-test") BeforeEach(func() { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) origSpec = config.Spec.DeepCopy() }) AfterEach(func() { By("Restoring CDIConfig to original state") err := utils.UpdateCDIConfig(f.CrClient, func(config *cdiv1.CDIConfigSpec) { origSpec.DeepCopyInto(config) }) Expect(err).ToNot(HaveOccurred()) Eventually(func() bool { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) return apiequality.Semantic.DeepEqual(config.Spec, *origSpec) }, timeout, pollingInterval).Should(BeTrue(), "CDIConfig not properly restored to original value") Eventually(func() bool { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) return !apiequality.Semantic.DeepEqual(config.Status, cdiv1.CDIConfigStatus{}) }, timeout, pollingInterval).Should(BeTrue(), "CDIConfig status not restored by config controller") }) DescribeTable("Should disallow invalid global filesystem overhead values", func(overhead string, success bool) { err := utils.UpdateCDIConfigWithOptions(f.CrClient, metav1.UpdateOptions{DryRun: []string{"All"}}, func(config *cdiv1.CDIConfigSpec) { config.FilesystemOverhead = &cdiv1.FilesystemOverhead{ Global: cdiv1.Percent(overhead), } }) if success { Expect(err).ToNot(HaveOccurred()) } else { Expect(err).To(HaveOccurred()) } }, Entry("[test_id:4714] Not a number1", "abc", false), Entry("[test_id:4674] Not a number2", "1.abc", false), Entry("[test_id:5011] Too big1", "1.0001", false), Entry("[test_id:5012] Too big2", "inf", false), Entry("[test_id:5013] Negative", "-0.1", false), Entry("one", "1", true), Entry("zero", "0", true), Entry("zero2", "0.0", true), ) DescribeTable("Per-storageClass filesystem overhead value", func(overhead string, success bool) { defaultSCName := utils.DefaultStorageClass.GetName() err := utils.UpdateCDIConfigWithOptions(f.CrClient, metav1.UpdateOptions{}, func(config *cdiv1.CDIConfigSpec) { config.FilesystemOverhead = &cdiv1.FilesystemOverhead{ Global: "0.99", // Used to easily test that the update happened StorageClass: map[string]cdiv1.Percent{defaultSCName: cdiv1.Percent(overhead)}, } }) if success { Expect(err).ToNot(HaveOccurred()) By("Waiting for the CDIConfig status to be updated by the controller") Eventually(func() bool { config, err := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) return config.Status.FilesystemOverhead.Global == cdiv1.Percent("0.99") }, timeout, pollingInterval).Should(BeTrue(), "CDIConfig not set") } else { Expect(err).To(HaveOccurred()) } config, _ := f.CdiClient.CdiV1beta1().CDIConfigs().Get(context.TODO(), common.ConfigName, metav1.GetOptions{}) if success { By(fmt.Sprintf("CDI Config spec %v", config.Spec.FilesystemOverhead.StorageClass)) By(fmt.Sprintf("CDI Config status %v", config.Status.FilesystemOverhead.StorageClass)) Expect(config.Status.FilesystemOverhead.StorageClass[defaultSCName]).To(Equal(cdiv1.Percent(overhead))) } else { Expect(config.Status.FilesystemOverhead.StorageClass[defaultSCName]).ToNot(Equal(cdiv1.Percent(overhead))) } }, Entry("[test_id:5014]should not update if not a number1", "abc", false), Entry("[test_id:5015]should not update if not a number2", "1.abc", false), Entry("[test_id:5016]should not update if too big1", "1.01", false), Entry("[test_id:5017]should not update if too big2", "inf", false), Entry("[test_id:5918]should not update if value is negative", "-0.1", false), Entry("should update if value is one", "1", true), Entry("should update if value is zero", "0", true), Entry("should update if value is zero2", "0.0", true), ) }) func createIngress(name, ns, service, hostUrl string) *extensionsv1beta1.Ingress { return &extensionsv1beta1.Ingress{ TypeMeta: metav1.TypeMeta{ APIVersion: "extensions/v1beta1", }, ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: ns, }, Spec: extensionsv1beta1.IngressSpec{ Backend: &extensionsv1beta1.IngressBackend{ ServiceName: service, ServicePort: intstr.IntOrString{ Type: intstr.Int, IntVal: 443, }, }, Rules: []extensionsv1beta1.IngressRule{ {Host: hostUrl}, }, }, } } func SetStorageClassDefault(f *framework.Framework, scName string, isDefault bool) error { sc, err := f.K8sClient.StorageV1().StorageClasses().Get(context.TODO(), scName, metav1.GetOptions{}) if err != nil { return err } ann := sc.GetAnnotations() if ann == nil { ann = make(map[string]string) } ann[controller.AnnDefaultStorageClass] = strconv.FormatBool(isDefault) sc.SetAnnotations(ann) _, err = f.K8sClient.StorageV1().StorageClasses().Update(context.TODO(), sc, metav1.UpdateOptions{}) Expect(err).ToNot(HaveOccurred()) Eventually(func() string { sc, err := f.K8sClient.StorageV1().StorageClasses().Get(context.TODO(), scName, metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) return sc.GetAnnotations()[controller.AnnDefaultStorageClass] }, time.Second*30, time.Second).Should(Equal(strconv.FormatBool(isDefault))) return nil }