Skip to content
53 changes: 53 additions & 0 deletions images/virtualization-artifact/pkg/builder/vdsnapshot/option.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
Copyright 2025 Flant JSC

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 vdsnapshot

import (
"github.com/deckhouse/virtualization-controller/pkg/builder/meta"
"github.com/deckhouse/virtualization/api/core/v1alpha2"
)

type Option func(vdsnapshot *v1alpha2.VirtualDiskSnapshot)

var (
WithName = meta.WithName[*v1alpha2.VirtualDiskSnapshot]
WithNamespace = meta.WithNamespace[*v1alpha2.VirtualDiskSnapshot]
WithGenerateName = meta.WithGenerateName[*v1alpha2.VirtualDiskSnapshot]
WithLabel = meta.WithLabel[*v1alpha2.VirtualDiskSnapshot]
WithLabels = meta.WithLabels[*v1alpha2.VirtualDiskSnapshot]
WithAnnotation = meta.WithAnnotation[*v1alpha2.VirtualDiskSnapshot]
WithAnnotations = meta.WithAnnotations[*v1alpha2.VirtualDiskSnapshot]
WithFinalizer = meta.WithFinalizer[*v1alpha2.VirtualDiskSnapshot]
)

func WithVirtualDiskName(virtualDiskName string) Option {
return func(vdsnapshot *v1alpha2.VirtualDiskSnapshot) {
vdsnapshot.Spec.VirtualDiskName = virtualDiskName
}
}

func WithVirtualDisk(vd *v1alpha2.VirtualDisk) Option {
return func(vdsnapshot *v1alpha2.VirtualDiskSnapshot) {
vdsnapshot.Spec.VirtualDiskName = vd.Name
}
}

func WithRequiredConsistency(requiredConsistency bool) Option {
return func(vdsnapshot *v1alpha2.VirtualDiskSnapshot) {
vdsnapshot.Spec.RequiredConsistency = requiredConsistency
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
Copyright 2025 Flant JSC

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 vdsnapshot

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/deckhouse/virtualization/api/core/v1alpha2"
)

func New(options ...Option) *v1alpha2.VirtualDiskSnapshot {
vdsnapshot := NewEmpty("", "")
ApplyOptions(vdsnapshot, options...)
return vdsnapshot
}

func ApplyOptions(vdsnapshot *v1alpha2.VirtualDiskSnapshot, opts ...Option) {
if vdsnapshot == nil {
return
}
for _, opt := range opts {
opt(vdsnapshot)
}
}

func NewEmpty(name, namespace string) *v1alpha2.VirtualDiskSnapshot {
return &v1alpha2.VirtualDiskSnapshot{
TypeMeta: metav1.TypeMeta{
APIVersion: v1alpha2.SchemeGroupVersion.String(),
Kind: v1alpha2.VirtualDiskSnapshotKind,
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
}
}
2 changes: 1 addition & 1 deletion images/virtualization-artifact/pkg/builder/vi/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func WithDataSourceContainerImage(image string, imagePullSecret v1alpha2.ImagePu
}
}

func WithDataSourceObjectRef(kind v1alpha2.VirtualImageObjectRefKind, name, namespace string) Option {
func WithDataSourceObjectRef(kind v1alpha2.VirtualImageObjectRefKind, name string) Option {
return func(vi *v1alpha2.VirtualImage) {
vi.Spec.DataSource = v1alpha2.VirtualImageDataSource{
Type: v1alpha2.DataSourceTypeObjectRef,
Expand Down
265 changes: 265 additions & 0 deletions test/e2e/blockdevice/creation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
/*
Copyright 2025 Flant JSC

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 blockdevice

import (
"context"
"fmt"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"sigs.k8s.io/controller-runtime/pkg/client"

cvibuilder "github.com/deckhouse/virtualization-controller/pkg/builder/cvi"
vdbuilder "github.com/deckhouse/virtualization-controller/pkg/builder/vd"
vdsnapshotbuilder "github.com/deckhouse/virtualization-controller/pkg/builder/vdsnapshot"
vibuilder "github.com/deckhouse/virtualization-controller/pkg/builder/vi"
vmbuilder "github.com/deckhouse/virtualization-controller/pkg/builder/vm"
"github.com/deckhouse/virtualization/api/core/v1alpha2"
"github.com/deckhouse/virtualization/test/e2e/internal/framework"
"github.com/deckhouse/virtualization/test/e2e/internal/object"
"github.com/deckhouse/virtualization/test/e2e/internal/util"
)

var _ = Describe("VirtualImageCreation", func() {
f := framework.NewFramework("vi-creation")

BeforeEach(func() {
f.Before()
DeferCleanup(f.After)
})

It("verifies the images are created successfully", func() {
const cviPrefix = "v12-e2e"
var (
vd *v1alpha2.VirtualDisk
vdSnapshot *v1alpha2.VirtualDiskSnapshot
vis []*v1alpha2.VirtualImage
cvis []*v1alpha2.ClusterVirtualImage

baseCvis []*v1alpha2.ClusterVirtualImage
baseVis []*v1alpha2.VirtualImage
)

By("Creating VirtualDisk", func() {
vd = vdbuilder.New(
vdbuilder.WithGenerateName("vd-"),
vdbuilder.WithNamespace(f.Namespace().Name),
vdbuilder.WithDataSourceHTTP(
&v1alpha2.DataSourceHTTP{
URL: object.ImageURLAlpineUEFIPerf,
},
),
)
err := f.CreateWithDeferredDeletion(context.Background(), vd)
Expect(err).NotTo(HaveOccurred())
vm := object.NewMinimalVM("vm-", f.Namespace().Name, vmbuilder.WithBlockDeviceRefs(v1alpha2.BlockDeviceSpecRef{
Kind: v1alpha2.VirtualDiskKind,
Name: vd.Name,
}))
err = f.CreateWithDeferredDeletion(context.Background(), vm)
Expect(err).NotTo(HaveOccurred())
util.UntilObjectPhase(string(v1alpha2.DiskReady), framework.LongTimeout, vd)
err = f.Delete(context.Background(), vm)
Expect(err).NotTo(HaveOccurred())
})

By("Creating VirtualDiskSnapshot", func() {
vdSnapshot = vdsnapshotbuilder.New(
vdsnapshotbuilder.WithGenerateName("vdsnapshot-"),
vdsnapshotbuilder.WithNamespace(f.Namespace().Name),
vdsnapshotbuilder.WithVirtualDiskName(vd.Name),
vdsnapshotbuilder.WithRequiredConsistency(true),
)
err := f.CreateWithDeferredDeletion(context.Background(), vdSnapshot)
Expect(err).NotTo(HaveOccurred())
util.UntilObjectPhase(string(v1alpha2.VirtualDiskSnapshotPhaseReady), framework.ShortTimeout, vdSnapshot)
})

By("Generating base cvis", func() {
baseCvis = append(baseCvis, object.NewGenerateContainerImageCVI(fmt.Sprintf("%s-cvi-ci-", cviPrefix)))
baseCvis = append(baseCvis, cvibuilder.New(
cvibuilder.WithGenerateName(fmt.Sprintf("%s-cvi-http-", cviPrefix)),
cvibuilder.WithDataSourceHTTP(
object.ImageURLAlpineUEFIPerf,
nil,
nil,
),
))
baseCvis = append(baseCvis, cvibuilder.New(
cvibuilder.WithGenerateName(fmt.Sprintf("%s-cvi-from-vd-", cviPrefix)),
cvibuilder.WithDataSourceObjectRef(v1alpha2.ClusterVirtualImageObjectRefKindVirtualDisk, vd.Name, f.Namespace().Name),
))
baseCvis = append(baseCvis, cvibuilder.New(
cvibuilder.WithGenerateName(fmt.Sprintf("%s-cvi-from-vds-", cviPrefix)),
cvibuilder.WithDataSourceObjectRef(v1alpha2.ClusterVirtualImageObjectRefKindVirtualDiskSnapshot, vdSnapshot.Name, f.Namespace().Name),
))
})

By("Generating base vis on dvcr", func() {
baseVis = append(baseVis, object.NewGeneratedContainerImageVI("vi-ci-", f.Namespace().Name))
baseVis = append(baseVis, vibuilder.New(
vibuilder.WithGenerateName("vi-http-"),
vibuilder.WithNamespace(f.Namespace().Name),
vibuilder.WithStorage(v1alpha2.StorageContainerRegistry),
vibuilder.WithDataSourceHTTP(
object.ImageURLAlpineUEFIPerf,
nil,
nil,
),
))
baseVis = append(baseVis, vibuilder.New(
vibuilder.WithGenerateName("vi-from-vd-"),
vibuilder.WithNamespace(f.Namespace().Name),
vibuilder.WithStorage(v1alpha2.StorageContainerRegistry),
vibuilder.WithDataSourceObjectRef(v1alpha2.VirtualImageObjectRefKindVirtualDisk, vd.Name),
))
baseVis = append(baseVis, vibuilder.New(
vibuilder.WithGenerateName("vi-from-vds-"),
vibuilder.WithNamespace(f.Namespace().Name),
vibuilder.WithStorage(v1alpha2.StorageContainerRegistry),
vibuilder.WithDataSourceObjectRef(v1alpha2.VirtualImageObjectRefKindVirtualDiskSnapshot, vdSnapshot.Name),
))
})

By("Generating base vis on pvc", func() {
baseVis = append(baseVis, object.NewGeneratedContainerImageVI("vi-pvc-ci-", f.Namespace().Name, vibuilder.WithStorage(v1alpha2.StoragePersistentVolumeClaim)))
baseVis = append(baseVis, vibuilder.New(
vibuilder.WithGenerateName("vi-http-"),
vibuilder.WithNamespace(f.Namespace().Name),
vibuilder.WithStorage(v1alpha2.StoragePersistentVolumeClaim),
vibuilder.WithDataSourceHTTP(
object.ImageURLAlpineUEFIPerf,
nil,
nil,
),
))
baseVis = append(baseVis, vibuilder.New(
vibuilder.WithGenerateName("vi-pvc-from-vd-"),
vibuilder.WithStorage(v1alpha2.StoragePersistentVolumeClaim),
vibuilder.WithNamespace(f.Namespace().Name),
vibuilder.WithDataSourceObjectRef(v1alpha2.VirtualImageObjectRefKindVirtualDisk, vd.Name),
))
baseVis = append(baseVis, vibuilder.New(
vibuilder.WithGenerateName("vi-pvc-from-vds-"),
vibuilder.WithStorage(v1alpha2.StoragePersistentVolumeClaim),
vibuilder.WithNamespace(f.Namespace().Name),
vibuilder.WithDataSourceObjectRef(v1alpha2.VirtualImageObjectRefKindVirtualDiskSnapshot, vdSnapshot.Name),
))
})

By("Creating base images", func() {
for _, cvi := range baseCvis {
err := f.CreateWithDeferredDeletion(context.Background(), cvi)
Expect(err).NotTo(HaveOccurred())
}
for _, vi := range baseVis {
err := f.CreateWithDeferredDeletion(context.Background(), vi)
Expect(err).NotTo(HaveOccurred())
}
})

By("Generating cvis from base cvis", func() {
for _, baseCvi := range baseCvis {
cvis = append(cvis, cvibuilder.New(
cvibuilder.WithName(fmt.Sprintf("%s-cvi-from-%s", cviPrefix, baseCvi.Name)),
cvibuilder.WithDataSourceObjectRef(v1alpha2.ClusterVirtualImageObjectRefKindClusterVirtualImage, baseCvi.Name, ""),
))
}
})

By("Generating cvis from base vis", func() {
for _, baseVi := range baseVis {
cvis = append(cvis, cvibuilder.New(
cvibuilder.WithName(fmt.Sprintf("%s-cvi-from-%s", cviPrefix, baseVi.Name)),
cvibuilder.WithDataSourceObjectRef(v1alpha2.ClusterVirtualImageObjectRefKindVirtualImage, baseVi.Name, baseVi.Namespace),
))
}
})

By("Generating dvcr vis from base cvis", func() {
for _, baseCvi := range baseCvis {
vis = append(vis, vibuilder.New(
vibuilder.WithName(fmt.Sprintf("vi-from-%s", baseCvi.Name)),
vibuilder.WithNamespace(f.Namespace().Name),
vibuilder.WithDataSourceObjectRef(v1alpha2.VirtualImageObjectRefKindClusterVirtualImage, baseCvi.Name),
vibuilder.WithStorage(v1alpha2.StorageContainerRegistry),
))
}
})

By("Generating dvcr vis from base vis", func() {
for _, baseVi := range baseVis {
vis = append(vis, vibuilder.New(
vibuilder.WithName(fmt.Sprintf("vi-from-%s", baseVi.Name)),
vibuilder.WithNamespace(f.Namespace().Name),
vibuilder.WithStorage(v1alpha2.StorageContainerRegistry),
vibuilder.WithDataSourceObjectRef(v1alpha2.VirtualImageObjectRefKindVirtualImage, baseVi.Name),
))
}
})

By("Generating pvc vis from base cvis", func() {
for _, baseCvi := range baseCvis {
vis = append(vis, vibuilder.New(
vibuilder.WithName(fmt.Sprintf("vi-pvc-from-%s", baseCvi.Name)),
vibuilder.WithNamespace(f.Namespace().Name),
vibuilder.WithDataSourceObjectRef(v1alpha2.VirtualImageObjectRefKindClusterVirtualImage, baseCvi.Name),
vibuilder.WithStorage(v1alpha2.StoragePersistentVolumeClaim),
))
}
})

By("Generating pvc vis from base vis", func() {
for _, baseVi := range baseVis {
vis = append(vis, vibuilder.New(
vibuilder.WithName(fmt.Sprintf("vi-pvc-from-%s", baseVi.Name)),
vibuilder.WithNamespace(f.Namespace().Name),
vibuilder.WithStorage(v1alpha2.StoragePersistentVolumeClaim),
vibuilder.WithDataSourceObjectRef(v1alpha2.VirtualImageObjectRefKindVirtualImage, baseVi.Name),
))
}
})

By("Creating images", func() {
for _, vi := range vis {
err := f.CreateWithDeferredDeletion(context.Background(), vi)
Expect(err).NotTo(HaveOccurred())
}

for _, cvi := range cvis {
err := f.CreateWithDeferredDeletion(context.Background(), cvi)
Expect(err).NotTo(HaveOccurred())
}
})

By("Verifying that images are ready", func() {
// Should check base images too
vis = append(baseVis, vis...)
cvis = append(baseCvis, cvis...)

var objects []client.Object
for _, vi := range vis {
objects = append(objects, vi)
}
for _, cvi := range cvis {
objects = append(objects, cvi)
}
util.UntilObjectPhase(string(v1alpha2.ImageReady), framework.LongTimeout, objects...)
})
})
})
1 change: 0 additions & 1 deletion test/e2e/default_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ testData:
diskResizing: "/tmp/testdata/disk-resizing"
imageHotplug: "/tmp/testdata/image-hotplug"
sizingPolicy: "/tmp/testdata/sizing-policy"
imagesCreation: "/tmp/testdata/images-creation"
importerNetworkPolicy: "/tmp/testdata/importer-network-policy"
vmConfiguration: "/tmp/testdata/vm-configuration"
vmLabelAnnotation: "/tmp/testdata/vm-label-annotation"
Expand Down
1 change: 1 addition & 0 deletions test/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

_ "github.com/deckhouse/virtualization/test/e2e/blockdevice"
"github.com/deckhouse/virtualization/test/e2e/controller"
"github.com/deckhouse/virtualization/test/e2e/legacy"
_ "github.com/deckhouse/virtualization/test/e2e/vm"
Expand Down
Loading
Loading