Skip to content

Commit

Permalink
tests for cdi datasource
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Henriksen <[email protected]>
mhenriks committed Jul 15, 2021
1 parent 4e3e60d commit d20b8a4
Showing 8 changed files with 294 additions and 12 deletions.
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -80,7 +80,6 @@ require (
)

replace (

github.com/go-kit/kit => github.com/go-kit/kit v0.3.0
github.com/golang/glog => ./staging/src/github.com/golang/glog
github.com/onsi/ginkgo => github.com/onsi/ginkgo v1.12.1
6 changes: 6 additions & 0 deletions pkg/util/types/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -23,19 +23,25 @@ go_library(
go_test(
name = "go_default_test",
srcs = [
"dv_test.go",
"pvc_test.go",
"types_suite_test.go",
],
embed = [":go_default_library"],
deps = [
"//staging/src/kubevirt.io/client-go/api/v1:go_default_library",
"//staging/src/kubevirt.io/client-go/generated/containerized-data-importer/clientset/versioned/fake:go_default_library",
"//staging/src/kubevirt.io/client-go/kubecli:go_default_library",
"//staging/src/kubevirt.io/client-go/testutils:go_default_library",
"//vendor/github.com/golang/mock/gomock:go_default_library",
"//vendor/github.com/onsi/ginkgo:go_default_library",
"//vendor/github.com/onsi/ginkgo/extensions/table:go_default_library",
"//vendor/github.com/onsi/gomega:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
"//vendor/kubevirt.io/containerized-data-importer/pkg/apis/core/v1beta1:go_default_library",
],
)
2 changes: 1 addition & 1 deletion pkg/util/types/dv.go
Original file line number Diff line number Diff line change
@@ -45,7 +45,7 @@ func GetCloneSource(ctx context.Context, client kubecli.KubevirtClient, vm *virt
if cloneSource.Namespace == "" {
cloneSource.Namespace = vm.Namespace
}
} else if dvSpec.SourceRef != nil {
} else if dvSpec.SourceRef != nil && dvSpec.SourceRef.Kind == "DataSource" {
ns := vm.Namespace
if dvSpec.SourceRef.Namespace != nil {
ns = *dvSpec.SourceRef.Namespace
147 changes: 147 additions & 0 deletions pkg/util/types/dv_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* This file is part of the KubeVirt project
*
* 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.
*
* Copyright 2018 Red Hat, Inc.
*
*/

package types

import (
"context"

. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"
. "github.com/onsi/gomega"

"github.com/golang/mock/gomock"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"

virtv1 "kubevirt.io/client-go/api/v1"
cdifake "kubevirt.io/client-go/generated/containerized-data-importer/clientset/versioned/fake"
"kubevirt.io/client-go/kubecli"
cdiv1 "kubevirt.io/containerized-data-importer/pkg/apis/core/v1beta1"
)

var _ = Describe("DataVolume utils test", func() {
Context("with VM", func() {
vm := &virtv1.VirtualMachine{
ObjectMeta: metav1.ObjectMeta{
Namespace: "vmnamespace",
Name: "vm",
},
}

createClient := func(cdiObjects ...runtime.Object) kubecli.KubevirtClient {
ctrl := gomock.NewController(GinkgoT())
virtClient := kubecli.NewMockKubevirtClient(ctrl)
cdiClient := cdifake.NewSimpleClientset(cdiObjects...)
virtClient.EXPECT().CdiClient().Return(cdiClient).AnyTimes()
return virtClient
}

It("should ignore DataVolume with no clone operation", func() {
dv := &cdiv1.DataVolumeSpec{
Source: &cdiv1.DataVolumeSource{
Blank: &cdiv1.DataVolumeBlankImage{},
},
}

cs, err := GetCloneSource(context.TODO(), createClient(), vm, dv)
Expect(err).ToNot(HaveOccurred())
Expect(cs).To(BeNil())
})

DescribeTable("should properly handle DataVolume clone source", func(sourceNamespace, expectedNamespace string) {
sourceName := "name"
dv := &cdiv1.DataVolumeSpec{
Source: &cdiv1.DataVolumeSource{
PVC: &cdiv1.DataVolumeSourcePVC{
Namespace: sourceNamespace,
Name: sourceName,
},
},
}

cs, err := GetCloneSource(context.TODO(), createClient(), vm, dv)
Expect(err).ToNot(HaveOccurred())
Expect(cs).ToNot(BeNil())
Expect(cs.Namespace).To(Equal(expectedNamespace))
Expect(cs.Name).To(Equal(sourceName))
},
Entry("source namespace not specified", "", vm.Namespace),
Entry("source namespace is specified", "ns2", "ns2"),
)

It("should error if DataSource does not exist", func() {
ns := "foo"
dv := &cdiv1.DataVolumeSpec{
SourceRef: &cdiv1.DataVolumeSourceRef{
Kind: "DataSource",
Namespace: &ns,
Name: "bar",
},
}

cs, err := GetCloneSource(context.TODO(), createClient(), vm, dv)
Expect(err).To(HaveOccurred())
Expect(cs).To(BeNil())
})

DescribeTable("should properly handle DataVolume clone sourceRef", func(sourceRefNamespace, sourceNamespace, expectedNamespace string) {
sourceRefName := "sourceRef"
sourceName := "name"

ref := &cdiv1.DataSource{
ObjectMeta: metav1.ObjectMeta{
Namespace: vm.Namespace,
Name: sourceRefName,
},
Spec: cdiv1.DataSourceSpec{
Source: cdiv1.DataSourceSource{
PVC: &cdiv1.DataVolumeSourcePVC{
Namespace: sourceNamespace,
Name: sourceName,
},
},
},
}

dv := &cdiv1.DataVolumeSpec{
SourceRef: &cdiv1.DataVolumeSourceRef{
Kind: "DataSource",
Name: sourceRefName,
},
}

if sourceRefNamespace != "" {
ref.Namespace = sourceRefNamespace
dv.SourceRef.Namespace = &sourceRefNamespace
}

cs, err := GetCloneSource(context.TODO(), createClient(ref), vm, dv)
Expect(err).ToNot(HaveOccurred())
Expect(cs).ToNot(BeNil())
Expect(cs.Namespace).To(Equal(expectedNamespace))
Expect(cs.Name).To(Equal(sourceName))
},
Entry("sourceRef namespace and source namespace not specified", "", "", vm.Namespace),
Entry("source namespace not specified", "foo", "", "foo"),
Entry("sourceRef namespace not specified", "", "bar", "bar"),
Entry("everything specified", "foo", "bar", "bar"),
)
})
})
Original file line number Diff line number Diff line change
@@ -72,6 +72,7 @@ go_test(
"//pkg/virt-operator/resource/generate/rbac:go_default_library",
"//staging/src/kubevirt.io/client-go/api/v1:go_default_library",
"//staging/src/kubevirt.io/client-go/apis/snapshot/v1alpha1:go_default_library",
"//staging/src/kubevirt.io/client-go/generated/containerized-data-importer/clientset/versioned/fake:go_default_library",
"//staging/src/kubevirt.io/client-go/generated/kubevirt/clientset/versioned/fake:go_default_library",
"//staging/src/kubevirt.io/client-go/kubecli:go_default_library",
"//staging/src/kubevirt.io/client-go/testutils:go_default_library",
Original file line number Diff line number Diff line change
@@ -38,6 +38,7 @@ import (
k8sfield "k8s.io/apimachinery/pkg/util/validation/field"

v1 "kubevirt.io/client-go/api/v1"
cdifake "kubevirt.io/client-go/generated/containerized-data-importer/clientset/versioned/fake"
"kubevirt.io/client-go/kubecli"
cdiv1 "kubevirt.io/containerized-data-importer/pkg/apis/core/v1beta1"
"kubevirt.io/kubevirt/pkg/testutils"
@@ -1117,6 +1118,91 @@ var _ = Describe("Validating VM Admitter", func() {
table.Entry("when everything suppied with 'sa' service account", "ns1", "ns2", "ns3", "sa", "ns3", "ns2", "sa"),
)

table.DescribeTable("should successfully authorize clone from sourceRef", func(arNamespace, vmNamespace, sourceRefNamespace,
sourceNamespace, serviceAccount, expectedSourceNamespace, expectedTargetNamespace, expectedServiceAccount string) {
sourceRefName := "sourceRef"
ds := &cdiv1.DataSource{
ObjectMeta: metav1.ObjectMeta{
Namespace: vmNamespace,
Name: sourceRefName,
},
Spec: cdiv1.DataSourceSpec{
Source: cdiv1.DataSourceSource{
PVC: &cdiv1.DataVolumeSourcePVC{
Name: "whocares",
},
},
},
}

vm := &v1.VirtualMachine{
ObjectMeta: metav1.ObjectMeta{
Namespace: vmNamespace,
},
Spec: v1.VirtualMachineSpec{
Template: &v1.VirtualMachineInstanceTemplateSpec{},
DataVolumeTemplates: []v1.DataVolumeTemplateSpec{
{
ObjectMeta: metav1.ObjectMeta{
Name: "whatever",
},
Spec: cdiv1.DataVolumeSpec{
SourceRef: &cdiv1.DataVolumeSourceRef{
Kind: "DataSource",
Name: sourceRefName,
},
},
},
},
},
}

if sourceRefNamespace != "" {
ds.Namespace = sourceRefNamespace
vm.Spec.DataVolumeTemplates[0].Spec.SourceRef.Namespace = &sourceRefNamespace
}

if sourceNamespace != "" {
ds.Spec.Source.PVC.Namespace = sourceNamespace
}

if serviceAccount != "" {
vm.Spec.Template.Spec.Volumes = []v1.Volume{
{
VolumeSource: v1.VolumeSource{
ServiceAccount: &v1.ServiceAccountVolumeSource{
ServiceAccountName: serviceAccount,
},
},
},
}
}

ar := &admissionv1.AdmissionRequest{
Namespace: arNamespace,
}

cdiClient := cdifake.NewSimpleClientset(ds)
virtClient.EXPECT().CdiClient().Return(cdiClient).AnyTimes()

vmsAdmitter.cloneAuthFunc = makeCloneAdmitFunc(expectedSourceNamespace, "whocares",
expectedTargetNamespace, expectedServiceAccount)
causes, err := vmsAdmitter.authorizeVirtualMachineSpec(ar, vm)
Expect(err).ToNot(HaveOccurred())
Expect(causes).To(BeEmpty())
},
table.Entry("when source namespace suppied", "ns1", "", "", "ns3", "", "ns3", "ns1", "default"),
table.Entry("when vm namespace suppied and source not", "ns1", "ns2", "", "", "", "ns2", "ns2", "default"),
table.Entry("when ar namespace suppied and vm/source not", "ns1", "", "", "", "", "ns1", "ns1", "default"),
table.Entry("when everything suppied with default service account", "ns1", "ns2", "", "ns3", "", "ns3", "ns2", "default"),
table.Entry("when everything suppied with 'sa' service account", "ns1", "ns2", "", "ns3", "sa", "ns3", "ns2", "sa"),
table.Entry("when source namespace and sourceRef namespace suppied", "ns1", "", "foo", "ns3", "", "ns3", "ns1", "default"),
table.Entry("when vm namespace and sourceRef namespace suppied and source not", "ns1", "ns2", "foo", "", "", "foo", "ns2", "default"),
table.Entry("when ar namespace and sourceRef namespace suppied and vm/source not", "ns1", "", "foo", "", "", "foo", "ns1", "default"),
table.Entry("when everything and sourceRef suppied with default service account", "ns1", "ns2", "foo", "ns3", "", "ns3", "ns2", "default"),
table.Entry("when everything and sourceRef suppied with 'sa' service account", "ns1", "ns2", "foo", "ns3", "sa", "ns3", "ns2", "sa"),
)

table.DescribeTable("should deny clone", func(sourceNamespace, sourceName, failMessage string, failErr error, expectedMessage string) {
vm := &v1.VirtualMachine{
Spec: v1.VirtualMachineSpec{
62 changes: 53 additions & 9 deletions pkg/virt-controller/watch/vm_test.go
Original file line number Diff line number Diff line change
@@ -701,6 +701,34 @@ var _ = Describe("VirtualMachine", func() {
},
}

ds := &cdiv1.DataSource{
ObjectMeta: metav1.ObjectMeta{
Namespace: "ns2",
Name: "source-ref",
},
Spec: cdiv1.DataSourceSpec{
Source: cdiv1.DataSourceSource{
PVC: &cdiv1.DataVolumeSourcePVC{
Namespace: "ns1",
Name: "source-pvc",
},
},
},
}

dv3 := &v1.DataVolumeTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Name: "dv3",
},
Spec: cdiv1.DataVolumeSpec{
SourceRef: &cdiv1.DataVolumeSourceRef{
Kind: "DataSource",
Namespace: &ds.Namespace,
Name: ds.Name,
},
},
}

serviceAccountVol := &v1.Volume{
Name: "sa",
VolumeSource: v1.VolumeSource{
@@ -710,7 +738,7 @@ var _ = Describe("VirtualMachine", func() {
},
}

table.DescribeTable("create clone DataVolume for VirtualMachineInstance", func(dv *v1.DataVolumeTemplateSpec, saVol *v1.Volume, fail bool) {
table.DescribeTable("create clone DataVolume for VirtualMachineInstance", func(dv *v1.DataVolumeTemplateSpec, saVol *v1.Volume, ds *cdiv1.DataSource, fail bool) {
vm, _ := DefaultVirtualMachine(true)
vm.Spec.Template.Spec.Volumes = append(vm.Spec.Template.Spec.Volumes,
v1.Volume{
@@ -738,14 +766,29 @@ var _ = Describe("VirtualMachine", func() {
vmInterface.EXPECT().UpdateStatus(gomock.Any()).Times(1).Return(vm, nil)
}

if ds != nil {
cdiClient.PrependReactor("get", "datasources", func(action testing.Action) (handled bool, obj runtime.Object, err error) {
ga := action.(testing.GetAction)
Expect(ga.GetNamespace()).To(Equal(ds.Namespace))
Expect(ga.GetName()).To(Equal(ds.Name))
return true, ds, nil
})
}

controller.cloneAuthFunc = func(pvcNamespace, pvcName, saNamespace, saName string) (bool, string, error) {
if dv.Spec.Source.PVC.Namespace != "" {
Expect(pvcNamespace).Should(Equal(dv.Spec.Source.PVC.Namespace))
if dv.Spec.Source != nil {
if dv.Spec.Source.PVC.Namespace != "" {
Expect(pvcNamespace).Should(Equal(dv.Spec.Source.PVC.Namespace))
} else {
Expect(pvcNamespace).Should(Equal(vm.Namespace))
}

Expect(pvcName).Should(Equal(dv.Spec.Source.PVC.Name))
} else {
Expect(pvcNamespace).Should(Equal(vm.Namespace))
Expect(pvcNamespace).Should(Equal(ds.Spec.Source.PVC.Namespace))
Expect(pvcName).Should(Equal(ds.Spec.Source.PVC.Name))
}

Expect(pvcName).Should(Equal(dv.Spec.Source.PVC.Name))
Expect(saNamespace).Should(Equal(vm.Namespace))

if saVol != nil {
@@ -769,10 +812,11 @@ var _ = Describe("VirtualMachine", func() {
testutils.ExpectEvent(recorder, SuccessfulDataVolumeCreateReason)
}
},
table.Entry("with auth and source namespace defined", dv1, serviceAccountVol, false),
table.Entry("with auth and no source namespace defined", dv2, serviceAccountVol, false),
table.Entry("with auth and source namespace no serviceaccount defined", dv1, nil, false),
table.Entry("with no auth and source namespace defined", dv1, serviceAccountVol, true),
table.Entry("with auth and source namespace defined", dv1, serviceAccountVol, nil, false),
table.Entry("with auth and no source namespace defined", dv2, serviceAccountVol, nil, false),
table.Entry("with auth and source namespace no serviceaccount defined", dv1, nil, nil, false),
table.Entry("with no auth and source namespace defined", dv1, serviceAccountVol, nil, true),
table.Entry("with auth, datasource and source namespace defined", dv3, serviceAccountVol, ds, false),
)
})

1 change: 0 additions & 1 deletion staging/src/kubevirt.io/client-go/go.mod
Original file line number Diff line number Diff line change
@@ -27,7 +27,6 @@ require (
)

replace (

github.com/go-kit/kit => github.com/go-kit/kit v0.3.0
github.com/onsi/ginkgo => github.com/onsi/ginkgo v1.12.1
github.com/onsi/gomega => github.com/onsi/gomega v1.10.1

0 comments on commit d20b8a4

Please sign in to comment.