containerized-data-importer/tests/operator_test.go
Adam Litke 724e9d8362
Add test-ids for new tests (#1256)
Signed-off-by: Adam Litke <alitke@redhat.com>
2020-06-24 22:16:11 +02:00

277 lines
9.6 KiB
Go

package tests_test
import (
"fmt"
"net/http"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
routev1 "github.com/openshift/api/route/v1"
routeclient "github.com/openshift/client-go/route/clientset/versioned"
secclient "github.com/openshift/client-go/security/clientset/versioned"
conditions "github.com/openshift/custom-resource-status/conditions/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
cdiv1alpha1 "kubevirt.io/containerized-data-importer/pkg/apis/core/v1alpha1"
"kubevirt.io/containerized-data-importer/pkg/common"
operatorcontroller "kubevirt.io/containerized-data-importer/pkg/operator/controller"
"kubevirt.io/containerized-data-importer/tests/framework"
"kubevirt.io/containerized-data-importer/tests/utils"
)
var _ = Describe("Operator tests", func() {
f := framework.NewFrameworkOrDie("operator-test")
It("[test_id:3951]should create a route in OpenShift", func() {
if !isOpenshift(f.K8sClient) {
Skip("This test is OpenShift specific")
}
routeClient, err := routeclient.NewForConfig(f.RestConfig)
Expect(err).ToNot(HaveOccurred())
r, err := routeClient.RouteV1().Routes(f.CdiInstallNs).Get("cdi-uploadproxy", metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
Expect(r.Spec.TLS.Termination).To(Equal(routev1.TLSTerminationReencrypt))
})
It("should create a prometheus service in cdi namespace", func() {
promService, err := f.K8sClient.CoreV1().Services(f.CdiInstallNs).Get(common.PrometheusServiceName, metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
Expect(promService.Spec.Ports[0].Name).To(Equal("metrics"))
Expect(promService.Spec.Selector[common.PrometheusLabel]).To(Equal(""))
originalTimeStamp := promService.ObjectMeta.CreationTimestamp
By("Deleting the service")
err = f.K8sClient.CoreV1().Services(f.CdiInstallNs).Delete(common.PrometheusServiceName, &metav1.DeleteOptions{})
Expect(err).ToNot(HaveOccurred())
By("Verifying the operator has re-created the service")
Eventually(func() bool {
promService, err = f.K8sClient.CoreV1().Services(f.CdiInstallNs).Get(common.PrometheusServiceName, metav1.GetOptions{})
if err == nil {
return originalTimeStamp.Before(&promService.ObjectMeta.CreationTimestamp)
}
return false
}, 1*time.Minute, 2*time.Second).Should(BeTrue())
Expect(promService.Spec.Ports[0].Name).To(Equal("metrics"))
Expect(promService.Spec.Selector[common.PrometheusLabel]).To(Equal(""))
})
It("[test_id:3952]add cdi-sa to containerized-data-importer scc", func() {
if !isOpenshift(f.K8sClient) {
Skip("This test is OpenShift specific")
}
secClient, err := secclient.NewForConfig(f.RestConfig)
Expect(err).ToNot(HaveOccurred())
scc, err := secClient.SecurityV1().SecurityContextConstraints().Get("containerized-data-importer", metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
cdiSA := fmt.Sprintf("system:serviceaccount:%s:cdi-sa", f.CdiInstallNs)
Expect(scc.Users).Should(ContainElement(cdiSA))
})
// Condition flags can be found here with their meaning https://github.com/kubevirt/hyperconverged-cluster-operator/blob/master/docs/conditions.md
It("[test_id:3953]Condition flags on CR should be healthy and operating", func() {
cdiObjects, err := f.CdiClient.CdiV1alpha1().CDIs().List(metav1.ListOptions{})
Expect(err).ToNot(HaveOccurred())
Expect(len(cdiObjects.Items)).To(Equal(1))
cdiObject := cdiObjects.Items[0]
conditionMap := operatorcontroller.GetConditionValues(cdiObject.Status.Conditions)
// Application should be fully operational and healthy.
Expect(conditionMap[conditions.ConditionAvailable]).To(Equal(corev1.ConditionTrue))
Expect(conditionMap[conditions.ConditionProgressing]).To(Equal(corev1.ConditionFalse))
Expect(conditionMap[conditions.ConditionDegraded]).To(Equal(corev1.ConditionFalse))
})
})
var _ = Describe("Operator delete CDI tests", func() {
var cr *cdiv1alpha1.CDI
f := framework.NewFrameworkOrDie("operator-delete-cdi-test")
BeforeEach(func() {
var err error
cr, err = f.CdiClient.CdiV1alpha1().CDIs().Get("cdi", metav1.GetOptions{})
if errors.IsNotFound(err) {
Skip("CDI CR 'cdi' does not exist. Probably managed by another operator so skipping.")
}
Expect(err).ToNot(HaveOccurred())
})
ensureCDI := func() {
if cr == nil {
return
}
cdi, err := f.CdiClient.CdiV1alpha1().CDIs().Get(cr.Name, metav1.GetOptions{})
if err == nil {
if cdi.DeletionTimestamp == nil {
cdi.Spec = cr.Spec
_, err = f.CdiClient.CdiV1alpha1().CDIs().Update(cdi)
Expect(err).ToNot(HaveOccurred())
return
}
Eventually(func() bool {
_, err = f.CdiClient.CdiV1alpha1().CDIs().Get(cr.Name, metav1.GetOptions{})
if errors.IsNotFound(err) {
return true
}
Expect(err).ToNot(HaveOccurred())
return false
}, 5*time.Minute, 2*time.Second).Should(BeTrue())
} else {
Expect(errors.IsNotFound(err)).To(BeTrue())
}
cdi = &cdiv1alpha1.CDI{
ObjectMeta: metav1.ObjectMeta{
Name: "cdi",
},
Spec: cr.Spec,
}
cdi, err = f.CdiClient.CdiV1alpha1().CDIs().Create(cdi)
Expect(err).ToNot(HaveOccurred())
Eventually(func() bool {
cdi, err = f.CdiClient.CdiV1alpha1().CDIs().Get(cr.Name, metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
Expect(cdi.Status.Phase).ShouldNot(Equal(cdiv1alpha1.CDIPhaseError))
for _, c := range cdi.Status.Conditions {
if c.Type == conditions.ConditionAvailable && c.Status == corev1.ConditionTrue {
return true
}
}
return false
}, 10*time.Minute, 2*time.Second).Should(BeTrue())
By("Verifying CDI config object exists, before continuing")
Eventually(func() bool {
_, err = f.CdiClient.CdiV1alpha1().CDIConfigs().Get(common.ConfigName, metav1.GetOptions{})
if k8serrors.IsNotFound(err) {
return false
}
Expect(err).ToNot(HaveOccurred(), "Unable to read CDI Config, %v, expect more failures", err)
return true
}, CompletionTimeout, assertionPollInterval).Should(BeTrue(), "Timeout reading CDI Config, expect more failures")
}
AfterEach(func() {
ensureCDI()
})
It("should remove/install CDI a number of times successfully", func() {
for i := 0; i < 10; i++ {
err := f.CdiClient.CdiV1alpha1().CDIs().Delete(cr.Name, &metav1.DeleteOptions{})
Expect(err).ToNot(HaveOccurred())
ensureCDI()
}
})
It("[test_id:3954]should delete an upload pod", func() {
dv := utils.NewDataVolumeForUpload("delete-me", "1Gi")
By("Creating datavolume")
dv, err := utils.CreateDataVolumeFromDefinition(f.CdiClient, f.Namespace.Name, dv)
Expect(err).ToNot(HaveOccurred())
By("Waiting for pod to be running")
Eventually(func() bool {
pod, err := f.K8sClient.CoreV1().Pods(dv.Namespace).Get("cdi-upload-"+dv.Name, metav1.GetOptions{})
if errors.IsNotFound(err) {
return false
}
Expect(err).ToNot(HaveOccurred())
return pod.Status.Phase == corev1.PodRunning
}, 2*time.Minute, 1*time.Second).Should(BeTrue())
By("Deleting CDI")
err = f.CdiClient.CdiV1alpha1().CDIs().Delete(cr.Name, &metav1.DeleteOptions{})
Expect(err).ToNot(HaveOccurred())
By("Waiting for pod to be deleted")
Eventually(func() bool {
_, err = f.K8sClient.CoreV1().Pods(dv.Namespace).Get("cdi-upload-"+dv.Name, metav1.GetOptions{})
if errors.IsNotFound(err) {
return true
}
Expect(err).ToNot(HaveOccurred())
return false
}, 2*time.Minute, 1*time.Second).Should(BeTrue())
})
It("[test_id:3955]should block CDI delete", func() {
uninstallStrategy := cdiv1alpha1.CDIUninstallStrategyBlockUninstallIfWorkloadsExist
By("Getting CDI resource")
cdi, err := f.CdiClient.CdiV1alpha1().CDIs().Get(cr.Name, metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
cdi.Spec.UninstallStrategy = &uninstallStrategy
_, err = f.CdiClient.CdiV1alpha1().CDIs().Update(cdi)
Expect(err).ToNot(HaveOccurred())
By("Waiting for update")
Eventually(func() bool {
cdi, err = f.CdiClient.CdiV1alpha1().CDIs().Get(cr.Name, metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
return cdi.Spec.UninstallStrategy != nil && *cdi.Spec.UninstallStrategy == uninstallStrategy
}, 2*time.Minute, 1*time.Second).Should(BeTrue())
By("Creating datavolume")
dv := utils.NewDataVolumeForUpload("delete-me", "1Gi")
dv, err = utils.CreateDataVolumeFromDefinition(f.CdiClient, f.Namespace.Name, dv)
Expect(err).ToNot(HaveOccurred())
By("Cannot delete CDI")
err = f.CdiClient.CdiV1alpha1().CDIs().Delete(cr.Name, &metav1.DeleteOptions{DryRun: []string{"All"}})
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("there are still DataVolumes present"))
err = f.CdiClient.CdiV1alpha1().DataVolumes(f.Namespace.Name).Delete(dv.Name, &metav1.DeleteOptions{})
Expect(err).ToNot(HaveOccurred())
By("Can delete CDI")
err = f.CdiClient.CdiV1alpha1().CDIs().Delete(cr.Name, &metav1.DeleteOptions{DryRun: []string{"All"}})
Expect(err).ToNot(HaveOccurred())
})
})
//IsOpenshift checks if we are on OpenShift platform
func isOpenshift(client kubernetes.Interface) bool {
//OpenShift 3.X check
result := client.Discovery().RESTClient().Get().AbsPath("/oapi/v1").Do()
var statusCode int
result.StatusCode(&statusCode)
if result.Error() == nil {
// It is OpenShift
if statusCode == http.StatusOK {
return true
}
} else {
// Got 404 so this is not Openshift 3.X, let's check OpenShift 4
result = client.Discovery().RESTClient().Get().AbsPath("/apis/route.openshift.io").Do()
var statusCode int
result.StatusCode(&statusCode)
if result.Error() == nil {
// It is OpenShift
if statusCode == http.StatusOK {
return true
}
}
}
return false
}