Skip to content

Commit 940de9f

Browse files
add descheduler
Signed-off-by: Yaroslav Borbat <yaroslav.borbat@flant.com>
1 parent 477b759 commit 940de9f

20 files changed

Lines changed: 950 additions & 66 deletions

File tree

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
Copyright 2025 Flant JSC
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package cvi
18+
19+
import (
20+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
22+
"github.com/deckhouse/virtualization/api/core/v1alpha2"
23+
)
24+
25+
func New(options ...Option) *v1alpha2.ClusterVirtualImage {
26+
cvi := NewEmpty("")
27+
ApplyOptions(cvi, options...)
28+
return cvi
29+
}
30+
31+
func ApplyOptions(cvi *v1alpha2.ClusterVirtualImage, opts ...Option) {
32+
if cvi == nil {
33+
return
34+
}
35+
for _, opt := range opts {
36+
opt(cvi)
37+
}
38+
}
39+
40+
func NewEmpty(name string) *v1alpha2.ClusterVirtualImage {
41+
return &v1alpha2.ClusterVirtualImage{
42+
TypeMeta: metav1.TypeMeta{
43+
APIVersion: v1alpha2.SchemeGroupVersion.String(),
44+
Kind: v1alpha2.ClusterVirtualImageKind,
45+
},
46+
ObjectMeta: metav1.ObjectMeta{
47+
Name: name,
48+
},
49+
}
50+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
Copyright 2025 Flant JSC
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package cvi
18+
19+
import (
20+
"github.com/deckhouse/virtualization-controller/pkg/builder/meta"
21+
"github.com/deckhouse/virtualization/api/core/v1alpha2"
22+
)
23+
24+
type Option func(vmop *v1alpha2.ClusterVirtualImage)
25+
26+
var (
27+
WithName = meta.WithName[*v1alpha2.ClusterVirtualImage]
28+
WithGenerateName = meta.WithGenerateName[*v1alpha2.ClusterVirtualImage]
29+
WithLabel = meta.WithLabel[*v1alpha2.ClusterVirtualImage]
30+
WithLabels = meta.WithLabels[*v1alpha2.ClusterVirtualImage]
31+
WithAnnotation = meta.WithAnnotation[*v1alpha2.ClusterVirtualImage]
32+
WithAnnotations = meta.WithAnnotations[*v1alpha2.ClusterVirtualImage]
33+
WithFinalizer = meta.WithFinalizer[*v1alpha2.ClusterVirtualImage]
34+
)
35+
36+
func WithDataSourceHTTP(url string, checksum *v1alpha2.Checksum, caBundle []byte) Option {
37+
return func(cvi *v1alpha2.ClusterVirtualImage) {
38+
cvi.Spec.DataSource = v1alpha2.ClusterVirtualImageDataSource{
39+
Type: v1alpha2.DataSourceTypeHTTP,
40+
HTTP: &v1alpha2.DataSourceHTTP{
41+
URL: url,
42+
Checksum: checksum,
43+
CABundle: caBundle,
44+
},
45+
}
46+
}
47+
}
48+
49+
func WithDataSourceContainerImage(image string, imagePullSecret v1alpha2.ImagePullSecret, caBundle []byte) Option {
50+
return func(cvi *v1alpha2.ClusterVirtualImage) {
51+
cvi.Spec.DataSource = v1alpha2.ClusterVirtualImageDataSource{
52+
Type: v1alpha2.DataSourceTypeContainerImage,
53+
ContainerImage: &v1alpha2.ClusterVirtualImageContainerImage{
54+
Image: image,
55+
ImagePullSecret: imagePullSecret,
56+
CABundle: caBundle,
57+
},
58+
}
59+
}
60+
}
61+
62+
func WithDataSourceObjectRef(kind v1alpha2.ClusterVirtualImageObjectRefKind, name, namespace string) Option {
63+
return func(cvi *v1alpha2.ClusterVirtualImage) {
64+
cvi.Spec.DataSource = v1alpha2.ClusterVirtualImageDataSource{
65+
Type: v1alpha2.DataSourceTypeObjectRef,
66+
ObjectRef: &v1alpha2.ClusterVirtualImageObjectRef{
67+
Kind: kind,
68+
Name: name,
69+
Namespace: namespace,
70+
},
71+
}
72+
}
73+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
Copyright 2025 Flant JSC
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package vd
18+
19+
import (
20+
"k8s.io/apimachinery/pkg/api/resource"
21+
"k8s.io/utils/ptr"
22+
23+
"github.com/deckhouse/virtualization-controller/pkg/builder/meta"
24+
"github.com/deckhouse/virtualization/api/core/v1alpha2"
25+
)
26+
27+
type Option func(vmop *v1alpha2.VirtualDisk)
28+
29+
var (
30+
WithName = meta.WithName[*v1alpha2.VirtualDisk]
31+
WithNamespace = meta.WithNamespace[*v1alpha2.VirtualDisk]
32+
WithGenerateName = meta.WithGenerateName[*v1alpha2.VirtualDisk]
33+
WithLabel = meta.WithLabel[*v1alpha2.VirtualDisk]
34+
WithLabels = meta.WithLabels[*v1alpha2.VirtualDisk]
35+
WithAnnotation = meta.WithAnnotation[*v1alpha2.VirtualDisk]
36+
WithAnnotations = meta.WithAnnotations[*v1alpha2.VirtualDisk]
37+
WithFinalizer = meta.WithFinalizer[*v1alpha2.VirtualDisk]
38+
)
39+
40+
func WithDataSourceHTTP(url string, checksum *v1alpha2.Checksum, caBundle []byte) Option {
41+
return func(vd *v1alpha2.VirtualDisk) {
42+
vd.Spec.DataSource = &v1alpha2.VirtualDiskDataSource{
43+
Type: v1alpha2.DataSourceTypeHTTP,
44+
HTTP: &v1alpha2.DataSourceHTTP{
45+
URL: url,
46+
Checksum: checksum,
47+
CABundle: caBundle,
48+
},
49+
}
50+
}
51+
}
52+
53+
func WithDataSourceContainerImage(image, imagePullSecretName string, caBundle []byte) Option {
54+
return func(vd *v1alpha2.VirtualDisk) {
55+
vd.Spec.DataSource = &v1alpha2.VirtualDiskDataSource{
56+
Type: v1alpha2.DataSourceTypeContainerImage,
57+
ContainerImage: &v1alpha2.VirtualDiskContainerImage{
58+
Image: image,
59+
ImagePullSecret: v1alpha2.ImagePullSecretName{
60+
Name: imagePullSecretName,
61+
},
62+
CABundle: caBundle,
63+
},
64+
}
65+
}
66+
}
67+
68+
func WithDataSourceObjectRef(kind v1alpha2.VirtualDiskObjectRefKind, name string) Option {
69+
return func(vd *v1alpha2.VirtualDisk) {
70+
vd.Spec.DataSource = &v1alpha2.VirtualDiskDataSource{
71+
Type: v1alpha2.DataSourceTypeObjectRef,
72+
ObjectRef: &v1alpha2.VirtualDiskObjectRef{
73+
Kind: kind,
74+
Name: name,
75+
},
76+
}
77+
}
78+
}
79+
80+
func WithDataSourceObjectRefFromCVI(cvi *v1alpha2.ClusterVirtualImage) Option {
81+
return WithDataSourceObjectRef(v1alpha2.VirtualDiskObjectRefKindClusterVirtualImage, cvi.Name)
82+
}
83+
84+
func WithDataSourceObjectRefFromVI(vi *v1alpha2.VirtualImage) Option {
85+
return WithDataSourceObjectRef(v1alpha2.VirtualDiskObjectRefKindVirtualImage, vi.Name)
86+
}
87+
88+
func WithPersistentVolumeClaim(storageClass *string, size *resource.Quantity) Option {
89+
return func(vd *v1alpha2.VirtualDisk) {
90+
vd.Spec.PersistentVolumeClaim = v1alpha2.VirtualDiskPersistentVolumeClaim{
91+
StorageClass: storageClass,
92+
Size: size,
93+
}
94+
}
95+
}
96+
97+
func WithStorageClass(storageClass string) Option {
98+
return func(vd *v1alpha2.VirtualDisk) {
99+
vd.Spec.PersistentVolumeClaim.StorageClass = ptr.To(storageClass)
100+
}
101+
}
102+
103+
func WithSize(size *resource.Quantity) Option {
104+
return func(vd *v1alpha2.VirtualDisk) {
105+
vd.Spec.PersistentVolumeClaim.Size = size
106+
}
107+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
Copyright 2025 Flant JSC
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package vd
18+
19+
import (
20+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
22+
"github.com/deckhouse/virtualization/api/core/v1alpha2"
23+
)
24+
25+
func New(options ...Option) *v1alpha2.VirtualDisk {
26+
vd := NewEmpty("", "")
27+
ApplyOptions(vd, options...)
28+
return vd
29+
}
30+
31+
func ApplyOptions(vd *v1alpha2.VirtualDisk, opts ...Option) {
32+
if vd == nil {
33+
return
34+
}
35+
for _, opt := range opts {
36+
opt(vd)
37+
}
38+
}
39+
40+
func NewEmpty(name, namespace string) *v1alpha2.VirtualDisk {
41+
return &v1alpha2.VirtualDisk{
42+
TypeMeta: metav1.TypeMeta{
43+
APIVersion: v1alpha2.SchemeGroupVersion.String(),
44+
Kind: v1alpha2.VirtualDiskKind,
45+
},
46+
ObjectMeta: metav1.ObjectMeta{
47+
Name: name,
48+
Namespace: namespace,
49+
},
50+
}
51+
}

images/virtualization-artifact/pkg/builder/vm/option.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,40 @@ func WithMemory(size resource.Quantity) Option {
4949
vm.Spec.Memory.Size = size
5050
}
5151
}
52+
53+
func WithDisks(disks ...*v1alpha2.VirtualDisk) Option {
54+
return func(vm *v1alpha2.VirtualMachine) {
55+
blockDeviceRefs := make([]v1alpha2.BlockDeviceSpecRef, 0, len(disks))
56+
for _, disk := range disks {
57+
blockDeviceRefs = append(blockDeviceRefs, v1alpha2.BlockDeviceSpecRef{
58+
Kind: v1alpha2.VirtualDiskKind,
59+
Name: disk.Name,
60+
})
61+
}
62+
vm.Spec.BlockDeviceRefs = append(vm.Spec.BlockDeviceRefs, blockDeviceRefs...)
63+
}
64+
}
65+
66+
func WithBlockDeviceRefs(refs ...v1alpha2.BlockDeviceSpecRef) Option {
67+
return func(vm *v1alpha2.VirtualMachine) {
68+
vm.Spec.BlockDeviceRefs = append(vm.Spec.BlockDeviceRefs, refs...)
69+
}
70+
}
71+
72+
func WithNodeSelector(nodeSelector map[string]string) Option {
73+
return func(vm *v1alpha2.VirtualMachine) {
74+
vm.Spec.NodeSelector = nodeSelector
75+
}
76+
}
77+
78+
func WithLiveMigrationPolicy(liveMigrationPolicy v1alpha2.LiveMigrationPolicy) Option {
79+
return func(vm *v1alpha2.VirtualMachine) {
80+
vm.Spec.LiveMigrationPolicy = liveMigrationPolicy
81+
}
82+
}
83+
84+
func WithVirtualMachineClass(class string) Option {
85+
return func(vm *v1alpha2.VirtualMachine) {
86+
vm.Spec.VirtualMachineClassName = class
87+
}
88+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{{- if (lookup "apiextensions.k8s.io/v1" "CustomResourceDefinition" "" "deschedulers.deckhouse.io") }}
2+
apiVersion: deckhouse.io/v1alpha2
3+
kind: Descheduler
4+
metadata:
5+
name: virtualization
6+
{{- include "helm_lib_module_labels" (list .) | nindent 2 }}
7+
spec:
8+
evictLocalStoragePods: true
9+
podLabelSelector:
10+
matchExpressions:
11+
- key: vm.kubevirt.internal.virtualization.deckhouse.io/name
12+
operator: Exists
13+
strategies:
14+
lowNodeUtilization:
15+
enabled: true
16+
thresholds:
17+
cpu: 30
18+
targetThresholds:
19+
cpu: 80
20+
removePodsViolatingInterPodAntiAffinity:
21+
enabled: true
22+
removePodsViolatingNodeAffinity:
23+
enabled: true
24+
nodeAffinityType:
25+
- requiredDuringSchedulingIgnoredDuringExecution
26+
{{- end }}

tests/e2e/config/config.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import (
2929

3030
yamlv3 "gopkg.in/yaml.v3"
3131
storagev1 "k8s.io/api/storage/v1"
32+
"k8s.io/cli-runtime/pkg/genericclioptions"
33+
"k8s.io/client-go/rest"
3234

3335
gt "github.com/deckhouse/virtualization/tests/e2e/git"
3436
kc "github.com/deckhouse/virtualization/tests/e2e/kubectl"
@@ -170,6 +172,26 @@ type ClusterTransport struct {
170172
InsecureTls bool `yaml:"insecureTls"`
171173
}
172174

175+
func (c ClusterTransport) RestConfig() (*rest.Config, error) {
176+
configFlags := genericclioptions.ConfigFlags{}
177+
if c.KubeConfig != "" {
178+
configFlags.KubeConfig = &c.KubeConfig
179+
}
180+
if c.Token != "" {
181+
configFlags.BearerToken = &c.Token
182+
}
183+
if c.InsecureTls {
184+
configFlags.Insecure = &c.InsecureTls
185+
}
186+
if c.CertificateAuthority != "" {
187+
configFlags.CAFile = &c.CertificateAuthority
188+
}
189+
if c.Endpoint != "" {
190+
configFlags.APIServer = &c.Endpoint
191+
}
192+
return configFlags.ToRESTConfig()
193+
}
194+
173195
type DisksConf struct {
174196
UploadHelperImage string `yaml:"uploadHelperImage"`
175197
CviTestDataDir string `yaml:"cviTestDataDir"`

0 commit comments

Comments
 (0)