Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
829a1cd
use precreated cvi for tests
universal-itengineer Mar 13, 2026
dd6e6a6
add seccomp curl pod
universal-itengineer Mar 13, 2026
0a59872
add info cvi created
universal-itengineer Mar 13, 2026
6b4371c
refactor complex test
universal-itengineer Mar 13, 2026
3905c13
try cvi for legacy
universal-itengineer Mar 16, 2026
af5aaf7
affinity-tolleration to cvi
universal-itengineer Mar 16, 2026
a69696c
disk-resizing to cvi
universal-itengineer Mar 16, 2026
bf93fa3
temporary comment delete cvi
universal-itengineer Mar 16, 2026
9863ef0
image-hotplug use precreated cvi
universal-itengineer Mar 16, 2026
89b4c33
add label lowcase
universal-itengineer Mar 16, 2026
4543616
vd-snapshots pre created cvi
universal-itengineer Mar 16, 2026
1de4180
vm-evacuation pre created cvi
universal-itengineer Mar 16, 2026
ddfbca0
vm-disk-attachment pre created cvi
universal-itengineer Mar 16, 2026
b59c389
vm-label-annotation pre created cvi
universal-itengineer Mar 16, 2026
6a3a437
vm-migration-cancel pre created cvi
universal-itengineer Mar 16, 2026
c8e70b6
vm-versions pre created cvi
universal-itengineer Mar 16, 2026
caa77f5
data_export to precreate cvi
universal-itengineer Mar 16, 2026
789460e
virtual_disk_provisioning precreate cvi
universal-itengineer Mar 16, 2026
406c207
modify object
universal-itengineer Mar 16, 2026
391e7be
refactor label Legacy
universal-itengineer Mar 17, 2026
35220af
refactor predefined cvi funcs
universal-itengineer Mar 17, 2026
bea156b
simple replace http vd to cvi [p1]
universal-itengineer Mar 26, 2026
e7e66d2
vd and vi to cvi [p2]
universal-itengineer Mar 26, 2026
e5e0c1a
volume migration vi to cvi [p3]
universal-itengineer Mar 26, 2026
8e270a8
snapshot vi to cvi [p4]
universal-itengineer Mar 26, 2026
46e2cdd
cvi for network tests [p5]
universal-itengineer Mar 26, 2026
c07d389
tpm to cvi [p6]
universal-itengineer Mar 26, 2026
9d781c0
fix cvi notification
universal-itengineer Mar 26, 2026
3555920
add cloud init for ubuntu and alpine
universal-itengineer Mar 27, 2026
f9065c3
refactor constants
universal-itengineer Mar 27, 2026
2f8064f
refactor cloud-init
universal-itengineer Mar 27, 2026
b8f5888
fix golint
universal-itengineer Mar 27, 2026
7c8040f
fix lint 1
universal-itengineer Mar 27, 2026
27b27d8
add nolint fo util.UntilObjectPhase in manager
universal-itengineer Mar 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions test/e2e/blockdevice/data_exports.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,7 @@ var _ = Describe("DataExports", label.Slow(), func() {
)

By("Creating root and data disks", func() {
vdRoot = vdbuilder.New(
vdbuilder.WithName("vd-root"),
vdbuilder.WithNamespace(f.Namespace().Name),
vdbuilder.WithDataSourceHTTP(&v1alpha2.DataSourceHTTP{
URL: object.ImageURLUbuntu,
}),
)
vdRoot = object.NewVDFromCVI("vd-root", f.Namespace().Name, object.PrecreatedCVIUbuntu)

vdData = vdbuilder.New(
vdbuilder.WithName("vd-data"),
Expand All @@ -111,7 +105,7 @@ var _ = Describe("DataExports", label.Slow(), func() {
v1alpha2.BlockDeviceSpecRef{Kind: v1alpha2.DiskDevice, Name: vdData.Name},
),
vmbuilder.WithRunPolicy(v1alpha2.AlwaysOnUnlessStoppedManually),
vmbuilder.WithProvisioningUserData(object.DefaultCloudInit),
vmbuilder.WithProvisioningUserData(object.UbuntuCloudInit),
)

err := f.CreateWithDeferredDeletion(context.Background(), vm)
Expand Down
17 changes: 3 additions & 14 deletions test/e2e/blockdevice/virtual_disk_provisioning.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (
"k8s.io/utils/ptr"

vdbuilder "github.com/deckhouse/virtualization-controller/pkg/builder/vd"
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"
Expand Down Expand Up @@ -55,13 +54,8 @@ var _ = Describe("VirtualDiskProvisioning", func() {
vm *v1alpha2.VirtualMachine
)

By("Creating VirtualImage", func() {
vi = vibuilder.New(
vibuilder.WithName("vi"),
vibuilder.WithNamespace(f.Namespace().Name),
vibuilder.WithDataSourceHTTP(object.ImageURLAlpineUEFI, nil, nil),
vibuilder.WithStorage(v1alpha2.StoragePersistentVolumeClaim),
)
By("Creating VirtualImage from precreated CVI", func() {
vi = object.NewGeneratedVIFromCVI("vi-", f.Namespace().Name, object.PrecreatedCVIAlpineUEFI)

err := f.CreateWithDeferredDeletion(context.Background(), vi)
Expect(err).NotTo(HaveOccurred())
Expand All @@ -72,12 +66,7 @@ var _ = Describe("VirtualDiskProvisioning", func() {
})

By("Creating VirtualDisk", func() {
vd = vdbuilder.New(
vdbuilder.WithName("vd"),
vdbuilder.WithNamespace(f.Namespace().Name),
vdbuilder.WithSize(ptr.To(resource.MustParse("350Mi"))),
vdbuilder.WithDataSourceObjectRefFromVI(vi),
)
vd = object.NewVDFromVI("vd", f.Namespace().Name, vi, vdbuilder.WithSize(ptr.To(resource.MustParse("350Mi"))))

err := f.CreateWithDeferredDeletion(context.Background(), vd)
Expect(err).NotTo(HaveOccurred())
Expand Down
7 changes: 5 additions & 2 deletions test/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,12 @@ func TestE2E(t *testing.T) {
var _ = SynchronizedBeforeSuite(func() {
controller.NewBeforeProcess1Body()
legacy.NewBeforeProcess1Body()
bootstrapPrecreatedCVIs()
}, func() {})

var _ = SynchronizedAfterSuite(func() {}, func() {
DeferCleanup(legacy.NewAfterAllProcessBody)
var _ = SynchronizedAfterSuite(func() {
cleanupPrecreatedCVIs()
}, func() {
legacy.NewAfterAllProcessBody()
controller.NewAfterAllProcessBody()
})
2 changes: 2 additions & 0 deletions test/e2e/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/deckhouse/virtualization/api v0.0.0-20240923080356-bb5809dba578
github.com/onsi/ginkgo/v2 v2.23.3
github.com/onsi/gomega v1.37.0
github.com/stretchr/testify v1.11.1
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.34.2
k8s.io/apimachinery v0.34.2
Expand Down Expand Up @@ -57,6 +58,7 @@ require (
github.com/openshift/custom-resource-status v1.1.2 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/spf13/cobra v1.9.1 // indirect
github.com/spf13/pflag v1.0.7 // indirect
github.com/x448/float16 v0.8.4 // indirect
Expand Down
22 changes: 22 additions & 0 deletions test/e2e/internal/config/cleanup.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,28 @@ import (
// PostCleanUpEnv defines an environment variable used to explicitly request the deletion of created/used resources.
const PostCleanUpEnv = "POST_CLEANUP"

// PrecreatedCVICleanupEnv defines an environment variable to explicitly enable deletion of precreated CVIs after the suite.
//
// By default, precreated CVIs are not deleted: they are shared across runs and may be reused.
// Set PRECREATED_CVI_CLEANUP=yes to delete them after the suite; unset, empty, or "no" means no deletion.
const PrecreatedCVICleanupEnv = "PRECREATED_CVI_CLEANUP"

func CheckPrecreatedCVICleanupOption() error {
env := os.Getenv(PrecreatedCVICleanupEnv)
switch env {
case "yes", "no", "":
return nil
default:
return fmt.Errorf("invalid value for %s env: %q (allowed: \"\", \"yes\", \"no\")", PrecreatedCVICleanupEnv, env)
}
}

// IsPrecreatedCVICleanupNeeded returns true only when PRECREATED_CVI_CLEANUP is explicitly set to "yes".
// Default (unset, empty, or "no"): precreated CVIs are not deleted after the suite.
func IsPrecreatedCVICleanupNeeded() bool {
return os.Getenv(PrecreatedCVICleanupEnv) == "yes"
}

func CheckWithPostCleanUpOption() error {
env := os.Getenv(PostCleanUpEnv)
switch env {
Expand Down
4 changes: 4 additions & 0 deletions test/e2e/internal/label/label.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,7 @@ func Slow() Labels {
func TPM() Labels {
return Label("TPM")
}

func Legacy() Labels {
return Label("Legacy")
}
80 changes: 80 additions & 0 deletions test/e2e/internal/object/cloud_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
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 object

import (
"fmt"

"k8s.io/utils/ptr"
"sigs.k8s.io/yaml"
)

// CloudConfig mirrors the cloud-init cloud-config YAML schema.
// Only the keys used by e2e tests are included.
// See https://cloudinit.readthedocs.io/en/latest/reference/modules.html
type CloudConfig struct {
PackageUpdate bool `json:"package_update,omitempty"`
Packages []string `json:"packages,omitempty"`
WriteFiles []WriteFile `json:"write_files,omitempty"`
Users []CloudConfigUser `json:"users,omitempty"`
Runcmd []string `json:"runcmd,omitempty"`
SSHPwauth *bool `json:"ssh_pwauth,omitempty"`
}

type CloudConfigUser struct {
Name string `json:"name"`
Passwd string `json:"passwd,omitempty"`
Shell string `json:"shell,omitempty"`
Sudo string `json:"sudo,omitempty"`
LockPasswd *bool `json:"lock_passwd,omitempty"`
SSHAuthorizedKeys []string `json:"ssh_authorized_keys,omitempty"`
}

type WriteFile struct {
Path string `json:"path"`
Permissions string `json:"permissions,omitempty"`
Content string `json:"content,omitempty"`
Append bool `json:"append,omitempty"`
}

const defaultSSHPublicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFxcXHmwaGnJ8scJaEN5RzklBPZpVSic4GdaAsKjQoeA your_email@example.com"

// DefaultCloudUser returns the standard e2e test user (cloud/cloud) with SSH key.
func DefaultCloudUser() CloudConfigUser {
return CloudConfigUser{
Name: DefaultUser,
Passwd: "$6$rounds=4096$vln/.aPHBOI7BMYR$bBMkqQvuGs5Gyd/1H5DP4m9HjQSy.kgrxpaGEHwkX7KEFV8BS.HZWPitAtZ2Vd8ZqIZRqmlykRCagTgPejt1i.",
Shell: "/bin/bash",
Sudo: "ALL=(ALL) NOPASSWD:ALL",
LockPasswd: ptr.To(false),
SSHAuthorizedKeys: []string{defaultSSHPublicKey},
}
}

var basePackages = []string{
"qemu-guest-agent", "curl", "bash", "sudo", "util-linux", "iperf3", "jq",
}

// Render serializes the CloudConfig to a valid cloud-init user-data string
// with the required #cloud-config header.
func (c CloudConfig) Render() string {
data, err := yaml.Marshal(c)
if err != nil {
panic(fmt.Sprintf("cloud-config marshal: %v", err))
}
return "#cloud-config\n" + string(data)
}
149 changes: 149 additions & 0 deletions test/e2e/internal/object/cloud_config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
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 object

import (
"strings"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"sigs.k8s.io/yaml"
)

func TestCloudConfigRender(t *testing.T) {
tests := []struct {
name string
rendered string
}{
{"AlpineCloudInit", AlpineCloudInit},
{"UbuntuCloudInit", UbuntuCloudInit},
{"PerfCloudInit", PerfCloudInit},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require.True(t, strings.HasPrefix(tt.rendered, "#cloud-config\n"),
"cloud-init must start with #cloud-config header")

var parsed map[string]interface{}
err := yaml.Unmarshal([]byte(tt.rendered), &parsed)
require.NoError(t, err, "cloud-init must be valid YAML")

assert.Equal(t, true, parsed["package_update"])

users, ok := parsed["users"].([]interface{})
require.True(t, ok, "users must be a list")
require.Len(t, users, 1)

user := users[0].(map[string]interface{})
assert.Equal(t, DefaultUser, user["name"])
assert.Equal(t, false, user["lock_passwd"])

keys, ok := user["ssh_authorized_keys"].([]interface{})
require.True(t, ok)
require.Len(t, keys, 1)

runcmd, ok := parsed["runcmd"].([]interface{})
require.True(t, ok, "runcmd must be a list")
assert.NotEmpty(t, runcmd)
})
}
}

func TestPerfCloudInitHasWriteFiles(t *testing.T) {
var parsed map[string]interface{}
err := yaml.Unmarshal([]byte(PerfCloudInit), &parsed)
require.NoError(t, err)

writeFiles, ok := parsed["write_files"].([]interface{})
require.True(t, ok, "PerfCloudInit must have write_files")
require.Len(t, writeFiles, 1)

wf := writeFiles[0].(map[string]interface{})
assert.Equal(t, "/usr/scripts/iperf3.sh", wf["path"])
assert.Equal(t, "0755", wf["permissions"])

content, ok := wf["content"].(string)
require.True(t, ok)
assert.Contains(t, content, "#!/bin/bash")
assert.Contains(t, content, "iperf3")
}

func TestPerfCloudInitGolden(t *testing.T) {
expected := `#cloud-config
package_update: true
packages:
- qemu-guest-agent
- curl
- bash
- sudo
- util-linux
- iperf3
- jq
- iputils
runcmd:
- /usr/scripts/iperf3.sh
- rc-update add qemu-guest-agent && rc-service qemu-guest-agent start
- rc-update add iperf3 && rc-service iperf3 start
- rc-update add sshd && rc-service sshd start
users:
- lock_passwd: false
name: cloud
passwd: $6$rounds=4096$vln/.aPHBOI7BMYR$bBMkqQvuGs5Gyd/1H5DP4m9HjQSy.kgrxpaGEHwkX7KEFV8BS.HZWPitAtZ2Vd8ZqIZRqmlykRCagTgPejt1i.
shell: /bin/bash
ssh_authorized_keys:
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFxcXHmwaGnJ8scJaEN5RzklBPZpVSic4GdaAsKjQoeA
your_email@example.com
sudo: ALL=(ALL) NOPASSWD:ALL
write_files:
- content: |
#!/bin/bash
cat > /etc/init.d/iperf3 <<-"EOF"
#!/sbin/openrc-run

name="iperf3"
description="iperf3 server"
command="/usr/bin/iperf3"
command_args="-s"
pidfile="/run/${name}.pid"
supervisor="supervise-daemon"
supervise_daemon_args="--respawn-delay 2 --stdout /var/log/iperf3.log --stderr /var/log/iperf3.log"

depend() {
need net
}

start_pre() {
checkpath --directory --owner root:root --mode 0755 /run
touch /var/log/iperf3.log
chmod 644 /var/log/iperf3.log
}

stop_post() {
logger -t iperf3 "Stopped by $(whoami) at $(date)"
rm -f "$pidfile"
}
EOF
chmod +x /etc/init.d/iperf3
rc-update add iperf3 default
path: /usr/scripts/iperf3.sh
permissions: "0755"
`

assert.Equal(t, expected, PerfCloudInit)
}
Loading
Loading