diff --git a/api/client/generated/clientset/versioned/clientset.go b/api/client/generated/clientset/versioned/clientset.go index d2a4e3bbec..e3027ebb46 100644 --- a/api/client/generated/clientset/versioned/clientset.go +++ b/api/client/generated/clientset/versioned/clientset.go @@ -23,6 +23,7 @@ import ( http "net/http" virtualizationv1alpha2 "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/typed/core/v1alpha2" + virtualizationv1alpha3 "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/typed/core/v1alpha3" discovery "k8s.io/client-go/discovery" rest "k8s.io/client-go/rest" flowcontrol "k8s.io/client-go/util/flowcontrol" @@ -31,12 +32,14 @@ import ( type Interface interface { Discovery() discovery.DiscoveryInterface VirtualizationV1alpha2() virtualizationv1alpha2.VirtualizationV1alpha2Interface + VirtualizationV1alpha3() virtualizationv1alpha3.VirtualizationV1alpha3Interface } // Clientset contains the clients for groups. type Clientset struct { *discovery.DiscoveryClient virtualizationV1alpha2 *virtualizationv1alpha2.VirtualizationV1alpha2Client + virtualizationV1alpha3 *virtualizationv1alpha3.VirtualizationV1alpha3Client } // VirtualizationV1alpha2 retrieves the VirtualizationV1alpha2Client @@ -44,6 +47,11 @@ func (c *Clientset) VirtualizationV1alpha2() virtualizationv1alpha2.Virtualizati return c.virtualizationV1alpha2 } +// VirtualizationV1alpha3 retrieves the VirtualizationV1alpha3Client +func (c *Clientset) VirtualizationV1alpha3() virtualizationv1alpha3.VirtualizationV1alpha3Interface { + return c.virtualizationV1alpha3 +} + // Discovery retrieves the DiscoveryClient func (c *Clientset) Discovery() discovery.DiscoveryInterface { if c == nil { @@ -92,6 +100,10 @@ func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, if err != nil { return nil, err } + cs.virtualizationV1alpha3, err = virtualizationv1alpha3.NewForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient) if err != nil { @@ -114,6 +126,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { func New(c rest.Interface) *Clientset { var cs Clientset cs.virtualizationV1alpha2 = virtualizationv1alpha2.New(c) + cs.virtualizationV1alpha3 = virtualizationv1alpha3.New(c) cs.DiscoveryClient = discovery.NewDiscoveryClient(c) return &cs diff --git a/api/client/generated/clientset/versioned/fake/clientset_generated.go b/api/client/generated/clientset/versioned/fake/clientset_generated.go index 732401580d..0976b8490f 100644 --- a/api/client/generated/clientset/versioned/fake/clientset_generated.go +++ b/api/client/generated/clientset/versioned/fake/clientset_generated.go @@ -22,6 +22,8 @@ import ( clientset "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned" virtualizationv1alpha2 "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/typed/core/v1alpha2" fakevirtualizationv1alpha2 "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/typed/core/v1alpha2/fake" + virtualizationv1alpha3 "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/typed/core/v1alpha3" + fakevirtualizationv1alpha3 "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/typed/core/v1alpha3/fake" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/watch" @@ -92,3 +94,8 @@ var ( func (c *Clientset) VirtualizationV1alpha2() virtualizationv1alpha2.VirtualizationV1alpha2Interface { return &fakevirtualizationv1alpha2.FakeVirtualizationV1alpha2{Fake: &c.Fake} } + +// VirtualizationV1alpha3 retrieves the VirtualizationV1alpha3Client +func (c *Clientset) VirtualizationV1alpha3() virtualizationv1alpha3.VirtualizationV1alpha3Interface { + return &fakevirtualizationv1alpha3.FakeVirtualizationV1alpha3{Fake: &c.Fake} +} diff --git a/api/client/generated/clientset/versioned/fake/register.go b/api/client/generated/clientset/versioned/fake/register.go index 1edca93ed7..599b8a83a9 100644 --- a/api/client/generated/clientset/versioned/fake/register.go +++ b/api/client/generated/clientset/versioned/fake/register.go @@ -20,6 +20,7 @@ package fake import ( virtualizationv1alpha2 "github.com/deckhouse/virtualization/api/core/v1alpha2" + virtualizationv1alpha3 "github.com/deckhouse/virtualization/api/core/v1alpha3" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -32,6 +33,7 @@ var codecs = serializer.NewCodecFactory(scheme) var localSchemeBuilder = runtime.SchemeBuilder{ virtualizationv1alpha2.AddToScheme, + virtualizationv1alpha3.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition diff --git a/api/client/generated/clientset/versioned/scheme/register.go b/api/client/generated/clientset/versioned/scheme/register.go index e4dd8c01b4..6e5bae592a 100644 --- a/api/client/generated/clientset/versioned/scheme/register.go +++ b/api/client/generated/clientset/versioned/scheme/register.go @@ -20,6 +20,7 @@ package scheme import ( virtualizationv1alpha2 "github.com/deckhouse/virtualization/api/core/v1alpha2" + virtualizationv1alpha3 "github.com/deckhouse/virtualization/api/core/v1alpha3" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -32,6 +33,7 @@ var Codecs = serializer.NewCodecFactory(Scheme) var ParameterCodec = runtime.NewParameterCodec(Scheme) var localSchemeBuilder = runtime.SchemeBuilder{ virtualizationv1alpha2.AddToScheme, + virtualizationv1alpha3.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition diff --git a/api/client/generated/clientset/versioned/typed/core/v1alpha3/core_client.go b/api/client/generated/clientset/versioned/typed/core/v1alpha3/core_client.go new file mode 100644 index 0000000000..667a073b12 --- /dev/null +++ b/api/client/generated/clientset/versioned/typed/core/v1alpha3/core_client.go @@ -0,0 +1,101 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + http "net/http" + + scheme "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/scheme" + corev1alpha3 "github.com/deckhouse/virtualization/api/core/v1alpha3" + rest "k8s.io/client-go/rest" +) + +type VirtualizationV1alpha3Interface interface { + RESTClient() rest.Interface + VirtualMachineClassesGetter +} + +// VirtualizationV1alpha3Client is used to interact with features provided by the virtualization.deckhouse.io group. +type VirtualizationV1alpha3Client struct { + restClient rest.Interface +} + +func (c *VirtualizationV1alpha3Client) VirtualMachineClasses() VirtualMachineClassInterface { + return newVirtualMachineClasses(c) +} + +// NewForConfig creates a new VirtualizationV1alpha3Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*VirtualizationV1alpha3Client, error) { + config := *c + setConfigDefaults(&config) + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new VirtualizationV1alpha3Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*VirtualizationV1alpha3Client, error) { + config := *c + setConfigDefaults(&config) + client, err := rest.RESTClientForConfigAndClient(&config, h) + if err != nil { + return nil, err + } + return &VirtualizationV1alpha3Client{client}, nil +} + +// NewForConfigOrDie creates a new VirtualizationV1alpha3Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *VirtualizationV1alpha3Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new VirtualizationV1alpha3Client for the given RESTClient. +func New(c rest.Interface) *VirtualizationV1alpha3Client { + return &VirtualizationV1alpha3Client{c} +} + +func setConfigDefaults(config *rest.Config) { + gv := corev1alpha3.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = rest.CodecFactoryForGeneratedClient(scheme.Scheme, scheme.Codecs).WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *VirtualizationV1alpha3Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/api/client/generated/clientset/versioned/typed/core/v1alpha3/doc.go b/api/client/generated/clientset/versioned/typed/core/v1alpha3/doc.go new file mode 100644 index 0000000000..cc161d1e74 --- /dev/null +++ b/api/client/generated/clientset/versioned/typed/core/v1alpha3/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1alpha3 diff --git a/api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/doc.go b/api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/doc.go new file mode 100644 index 0000000000..302a814007 --- /dev/null +++ b/api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/fake_core_client.go b/api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/fake_core_client.go new file mode 100644 index 0000000000..e86d5e9b67 --- /dev/null +++ b/api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/fake_core_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha3 "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/typed/core/v1alpha3" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeVirtualizationV1alpha3 struct { + *testing.Fake +} + +func (c *FakeVirtualizationV1alpha3) VirtualMachineClasses() v1alpha3.VirtualMachineClassInterface { + return newFakeVirtualMachineClasses(c) +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeVirtualizationV1alpha3) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/fake_virtualmachineclass.go b/api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/fake_virtualmachineclass.go new file mode 100644 index 0000000000..b00b1bd86e --- /dev/null +++ b/api/client/generated/clientset/versioned/typed/core/v1alpha3/fake/fake_virtualmachineclass.go @@ -0,0 +1,52 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + corev1alpha3 "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/typed/core/v1alpha3" + v1alpha3 "github.com/deckhouse/virtualization/api/core/v1alpha3" + gentype "k8s.io/client-go/gentype" +) + +// fakeVirtualMachineClasses implements VirtualMachineClassInterface +type fakeVirtualMachineClasses struct { + *gentype.FakeClientWithList[*v1alpha3.VirtualMachineClass, *v1alpha3.VirtualMachineClassList] + Fake *FakeVirtualizationV1alpha3 +} + +func newFakeVirtualMachineClasses(fake *FakeVirtualizationV1alpha3) corev1alpha3.VirtualMachineClassInterface { + return &fakeVirtualMachineClasses{ + gentype.NewFakeClientWithList[*v1alpha3.VirtualMachineClass, *v1alpha3.VirtualMachineClassList]( + fake.Fake, + "", + v1alpha3.SchemeGroupVersion.WithResource("virtualmachineclasses"), + v1alpha3.SchemeGroupVersion.WithKind("VirtualMachineClass"), + func() *v1alpha3.VirtualMachineClass { return &v1alpha3.VirtualMachineClass{} }, + func() *v1alpha3.VirtualMachineClassList { return &v1alpha3.VirtualMachineClassList{} }, + func(dst, src *v1alpha3.VirtualMachineClassList) { dst.ListMeta = src.ListMeta }, + func(list *v1alpha3.VirtualMachineClassList) []*v1alpha3.VirtualMachineClass { + return gentype.ToPointerSlice(list.Items) + }, + func(list *v1alpha3.VirtualMachineClassList, items []*v1alpha3.VirtualMachineClass) { + list.Items = gentype.FromPointerSlice(items) + }, + ), + fake, + } +} diff --git a/api/client/generated/clientset/versioned/typed/core/v1alpha3/generated_expansion.go b/api/client/generated/clientset/versioned/typed/core/v1alpha3/generated_expansion.go new file mode 100644 index 0000000000..4d90e21047 --- /dev/null +++ b/api/client/generated/clientset/versioned/typed/core/v1alpha3/generated_expansion.go @@ -0,0 +1,21 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha3 + +type VirtualMachineClassExpansion interface{} diff --git a/api/client/generated/clientset/versioned/typed/core/v1alpha3/virtualmachineclass.go b/api/client/generated/clientset/versioned/typed/core/v1alpha3/virtualmachineclass.go new file mode 100644 index 0000000000..86c69a1c87 --- /dev/null +++ b/api/client/generated/clientset/versioned/typed/core/v1alpha3/virtualmachineclass.go @@ -0,0 +1,70 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + context "context" + + scheme "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned/scheme" + corev1alpha3 "github.com/deckhouse/virtualization/api/core/v1alpha3" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" +) + +// VirtualMachineClassesGetter has a method to return a VirtualMachineClassInterface. +// A group's client should implement this interface. +type VirtualMachineClassesGetter interface { + VirtualMachineClasses() VirtualMachineClassInterface +} + +// VirtualMachineClassInterface has methods to work with VirtualMachineClass resources. +type VirtualMachineClassInterface interface { + Create(ctx context.Context, virtualMachineClass *corev1alpha3.VirtualMachineClass, opts v1.CreateOptions) (*corev1alpha3.VirtualMachineClass, error) + Update(ctx context.Context, virtualMachineClass *corev1alpha3.VirtualMachineClass, opts v1.UpdateOptions) (*corev1alpha3.VirtualMachineClass, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, virtualMachineClass *corev1alpha3.VirtualMachineClass, opts v1.UpdateOptions) (*corev1alpha3.VirtualMachineClass, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*corev1alpha3.VirtualMachineClass, error) + List(ctx context.Context, opts v1.ListOptions) (*corev1alpha3.VirtualMachineClassList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *corev1alpha3.VirtualMachineClass, err error) + VirtualMachineClassExpansion +} + +// virtualMachineClasses implements VirtualMachineClassInterface +type virtualMachineClasses struct { + *gentype.ClientWithList[*corev1alpha3.VirtualMachineClass, *corev1alpha3.VirtualMachineClassList] +} + +// newVirtualMachineClasses returns a VirtualMachineClasses +func newVirtualMachineClasses(c *VirtualizationV1alpha3Client) *virtualMachineClasses { + return &virtualMachineClasses{ + gentype.NewClientWithList[*corev1alpha3.VirtualMachineClass, *corev1alpha3.VirtualMachineClassList]( + "virtualmachineclasses", + c.RESTClient(), + scheme.ParameterCodec, + "", + func() *corev1alpha3.VirtualMachineClass { return &corev1alpha3.VirtualMachineClass{} }, + func() *corev1alpha3.VirtualMachineClassList { return &corev1alpha3.VirtualMachineClassList{} }, + ), + } +} diff --git a/api/client/generated/informers/externalversions/core/interface.go b/api/client/generated/informers/externalversions/core/interface.go index 1364a78eb7..f1da9e577c 100644 --- a/api/client/generated/informers/externalversions/core/interface.go +++ b/api/client/generated/informers/externalversions/core/interface.go @@ -20,6 +20,7 @@ package core import ( v1alpha2 "github.com/deckhouse/virtualization/api/client/generated/informers/externalversions/core/v1alpha2" + v1alpha3 "github.com/deckhouse/virtualization/api/client/generated/informers/externalversions/core/v1alpha3" internalinterfaces "github.com/deckhouse/virtualization/api/client/generated/informers/externalversions/internalinterfaces" ) @@ -27,6 +28,8 @@ import ( type Interface interface { // V1alpha2 provides access to shared informers for resources in V1alpha2. V1alpha2() v1alpha2.Interface + // V1alpha3 provides access to shared informers for resources in V1alpha3. + V1alpha3() v1alpha3.Interface } type group struct { @@ -44,3 +47,8 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList func (g *group) V1alpha2() v1alpha2.Interface { return v1alpha2.New(g.factory, g.namespace, g.tweakListOptions) } + +// V1alpha3 returns a new v1alpha3.Interface. +func (g *group) V1alpha3() v1alpha3.Interface { + return v1alpha3.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/api/client/generated/informers/externalversions/core/v1alpha3/interface.go b/api/client/generated/informers/externalversions/core/v1alpha3/interface.go new file mode 100644 index 0000000000..e201f89fa0 --- /dev/null +++ b/api/client/generated/informers/externalversions/core/v1alpha3/interface.go @@ -0,0 +1,45 @@ +/* +Copyright 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + internalinterfaces "github.com/deckhouse/virtualization/api/client/generated/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // VirtualMachineClasses returns a VirtualMachineClassInformer. + VirtualMachineClasses() VirtualMachineClassInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// VirtualMachineClasses returns a VirtualMachineClassInformer. +func (v *version) VirtualMachineClasses() VirtualMachineClassInformer { + return &virtualMachineClassInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} diff --git a/api/client/generated/informers/externalversions/core/v1alpha3/virtualmachineclass.go b/api/client/generated/informers/externalversions/core/v1alpha3/virtualmachineclass.go new file mode 100644 index 0000000000..f94694cc8e --- /dev/null +++ b/api/client/generated/informers/externalversions/core/v1alpha3/virtualmachineclass.go @@ -0,0 +1,101 @@ +/* +Copyright 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + context "context" + time "time" + + versioned "github.com/deckhouse/virtualization/api/client/generated/clientset/versioned" + internalinterfaces "github.com/deckhouse/virtualization/api/client/generated/informers/externalversions/internalinterfaces" + corev1alpha3 "github.com/deckhouse/virtualization/api/client/generated/listers/core/v1alpha3" + apicorev1alpha3 "github.com/deckhouse/virtualization/api/core/v1alpha3" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// VirtualMachineClassInformer provides access to a shared informer and lister for +// VirtualMachineClasses. +type VirtualMachineClassInformer interface { + Informer() cache.SharedIndexInformer + Lister() corev1alpha3.VirtualMachineClassLister +} + +type virtualMachineClassInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewVirtualMachineClassInformer constructs a new informer for VirtualMachineClass type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewVirtualMachineClassInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredVirtualMachineClassInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredVirtualMachineClassInformer constructs a new informer for VirtualMachineClass type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredVirtualMachineClassInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.VirtualizationV1alpha3().VirtualMachineClasses().List(context.Background(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.VirtualizationV1alpha3().VirtualMachineClasses().Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.VirtualizationV1alpha3().VirtualMachineClasses().List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.VirtualizationV1alpha3().VirtualMachineClasses().Watch(ctx, options) + }, + }, + &apicorev1alpha3.VirtualMachineClass{}, + resyncPeriod, + indexers, + ) +} + +func (f *virtualMachineClassInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredVirtualMachineClassInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *virtualMachineClassInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apicorev1alpha3.VirtualMachineClass{}, f.defaultInformer) +} + +func (f *virtualMachineClassInformer) Lister() corev1alpha3.VirtualMachineClassLister { + return corev1alpha3.NewVirtualMachineClassLister(f.Informer().GetIndexer()) +} diff --git a/api/client/generated/informers/externalversions/generic.go b/api/client/generated/informers/externalversions/generic.go index 1d37a9b7ae..938b674b16 100644 --- a/api/client/generated/informers/externalversions/generic.go +++ b/api/client/generated/informers/externalversions/generic.go @@ -22,6 +22,7 @@ import ( fmt "fmt" v1alpha2 "github.com/deckhouse/virtualization/api/core/v1alpha2" + v1alpha3 "github.com/deckhouse/virtualization/api/core/v1alpha3" schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" ) @@ -82,6 +83,10 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource case v1alpha2.SchemeGroupVersion.WithResource("virtualmachinesnapshots"): return &genericInformer{resource: resource.GroupResource(), informer: f.Virtualization().V1alpha2().VirtualMachineSnapshots().Informer()}, nil + // Group=virtualization.deckhouse.io, Version=v1alpha3 + case v1alpha3.SchemeGroupVersion.WithResource("virtualmachineclasses"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Virtualization().V1alpha3().VirtualMachineClasses().Informer()}, nil + } return nil, fmt.Errorf("no informer found for %v", resource) diff --git a/api/client/generated/listers/core/v1alpha3/expansion_generated.go b/api/client/generated/listers/core/v1alpha3/expansion_generated.go new file mode 100644 index 0000000000..4aed995351 --- /dev/null +++ b/api/client/generated/listers/core/v1alpha3/expansion_generated.go @@ -0,0 +1,23 @@ +/* +Copyright 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha3 + +// VirtualMachineClassListerExpansion allows custom methods to be added to +// VirtualMachineClassLister. +type VirtualMachineClassListerExpansion interface{} diff --git a/api/client/generated/listers/core/v1alpha3/virtualmachineclass.go b/api/client/generated/listers/core/v1alpha3/virtualmachineclass.go new file mode 100644 index 0000000000..f3616caec8 --- /dev/null +++ b/api/client/generated/listers/core/v1alpha3/virtualmachineclass.go @@ -0,0 +1,48 @@ +/* +Copyright 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + corev1alpha3 "github.com/deckhouse/virtualization/api/core/v1alpha3" + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" +) + +// VirtualMachineClassLister helps list VirtualMachineClasses. +// All objects returned here must be treated as read-only. +type VirtualMachineClassLister interface { + // List lists all VirtualMachineClasses in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*corev1alpha3.VirtualMachineClass, err error) + // Get retrieves the VirtualMachineClass from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*corev1alpha3.VirtualMachineClass, error) + VirtualMachineClassListerExpansion +} + +// virtualMachineClassLister implements the VirtualMachineClassLister interface. +type virtualMachineClassLister struct { + listers.ResourceIndexer[*corev1alpha3.VirtualMachineClass] +} + +// NewVirtualMachineClassLister returns a new VirtualMachineClassLister. +func NewVirtualMachineClassLister(indexer cache.Indexer) VirtualMachineClassLister { + return &virtualMachineClassLister{listers.New[*corev1alpha3.VirtualMachineClass](indexer, corev1alpha3.Resource("virtualmachineclass"))} +} diff --git a/api/core/v1alpha2/virtual_machine_class.go b/api/core/v1alpha2/virtual_machine_class.go index 1df0a83122..41ffa49316 100644 --- a/api/core/v1alpha2/virtual_machine_class.go +++ b/api/core/v1alpha2/virtual_machine_class.go @@ -36,6 +36,7 @@ const ( // +kubebuilder:metadata:labels={heritage=deckhouse,module=virtualization,backup.deckhouse.io/cluster-config=true} // +kubebuilder:subresource:status // +kubebuilder:resource:categories={virtualization-cluster},scope=Cluster,shortName={vmc,vmclass},singular=virtualmachineclass +// +kubebuilder:storageversion // +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="VirtualMachineClass phase." // +kubebuilder:printcolumn:name="IsDefault",type="string",JSONPath=".metadata.annotations.virtualmachineclass\\.virtualization\\.deckhouse\\.io\\/is-default-class",description="Default class for virtual machines without specified class." // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time of resource creation." diff --git a/api/core/v1alpha2/virtual_machine_class_conversion.go b/api/core/v1alpha2/virtual_machine_class_conversion.go new file mode 100644 index 0000000000..0a88b03f14 --- /dev/null +++ b/api/core/v1alpha2/virtual_machine_class_conversion.go @@ -0,0 +1,19 @@ +/* +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 v1alpha2 + +func (*VirtualMachineClass) Hub() {} diff --git a/api/core/v1alpha3/conversion_suite_test.go b/api/core/v1alpha3/conversion_suite_test.go new file mode 100644 index 0000000000..8499fededf --- /dev/null +++ b/api/core/v1alpha3/conversion_suite_test.go @@ -0,0 +1,29 @@ +/* +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 v1alpha3 + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestConversion(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "VirtualMachineClass Conversion Suite") +} diff --git a/api/core/v1alpha3/doc.go b/api/core/v1alpha3/doc.go new file mode 100644 index 0000000000..0d53bde091 --- /dev/null +++ b/api/core/v1alpha3/doc.go @@ -0,0 +1,22 @@ +/* +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. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:openapi-gen=true + +// Package v1alpha3 is the v1alpha3 version of the API. +// +groupName=virtualization.deckhouse.io +package v1alpha3 diff --git a/api/core/v1alpha3/register.go b/api/core/v1alpha3/register.go new file mode 100644 index 0000000000..0028d52785 --- /dev/null +++ b/api/core/v1alpha3/register.go @@ -0,0 +1,64 @@ +/* +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 v1alpha3 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + "github.com/deckhouse/virtualization/api/core" +) + +const Version = "v1alpha3" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: core.GroupName, Version: Version} + +// VirtualMachineClassGVK is group version kind for VirtualMachineClass +var VirtualMachineClassGVK = schema.GroupVersionKind{Group: SchemeGroupVersion.Group, Version: SchemeGroupVersion.Version, Kind: VirtualMachineClassKind} + +// Kind takes an unqualified kind and returns back a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +func GroupVersionResource(resource string) schema.GroupVersionResource { + return SchemeGroupVersion.WithResource(resource) +} + +var ( + // SchemeBuilder tbd + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + // AddToScheme tbd + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &VirtualMachineClass{}, + &VirtualMachineClassList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/api/core/v1alpha3/virtual_machine_class.go b/api/core/v1alpha3/virtual_machine_class.go new file mode 100644 index 0000000000..43f388cc7d --- /dev/null +++ b/api/core/v1alpha3/virtual_machine_class.go @@ -0,0 +1,243 @@ +/* +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. +*/ + +// +kubebuilder:object:generate=true +// +groupName=virtualization.deckhouse.io +package v1alpha3 + +import ( + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + VirtualMachineClassKind = "VirtualMachineClass" + VirtualMachineClassResource = "virtualmachineclasses" +) + +// VirtualMachineClass resource describes CPU requirements, node placement, and sizing policy for VM resources. +// A resource cannot be deleted as long as it is used in one of the VMs. +// +// +kubebuilder:object:root=true +// +kubebuilder:metadata:labels={heritage=deckhouse,module=virtualization,backup.deckhouse.io/cluster-config=true} +// +kubebuilder:subresource:status +// +kubebuilder:resource:categories={virtualization-cluster},scope=Cluster,shortName={vmc,vmclass},singular=virtualmachineclass +// +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="VirtualMachineClass phase." +// +kubebuilder:printcolumn:name="IsDefault",type="string",JSONPath=".metadata.annotations.virtualmachineclass\\.virtualization\\.deckhouse\\.io\\/is-default-class",description="Default class for virtual machines without specified class." +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time of resource creation." +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type VirtualMachineClass struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec VirtualMachineClassSpec `json:"spec"` + Status VirtualMachineClassStatus `json:"status,omitempty"` +} + +// VirtualMachineClassList contains a list of VirtualMachineClasses. +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type VirtualMachineClassList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + // Items provides a list of VirtualMachineClasses. + Items []VirtualMachineClass `json:"items"` +} + +type VirtualMachineClassSpec struct { + NodeSelector NodeSelector `json:"nodeSelector,omitempty"` + // Tolerations are the same as `spec.tolerations` for [pods](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/). + // These tolerations will be merged with the tolerations specified in the VirtualMachine resource. VirtualMachine tolerations have a higher priority. + Tolerations []corev1.Toleration `json:"tolerations,omitempty"` + // +kubebuilder:validation:Required + CPU CPU `json:"cpu"` + SizingPolicies []SizingPolicy `json:"sizingPolicies,omitempty"` +} + +// NodeSelector defines the nodes targeted for VM scheduling. +type NodeSelector struct { + // A map of {key,value} pairs. + // A single {key,value} pair in the matchLabels map is equivalent to an element of matchExpressions whose key field is "key", operator is "In", and the value array contains only "value". + // The requirements are ANDed. + MatchLabels map[string]string `json:"matchLabels,omitempty"` + // A list of node selector requirements by node's labels. + MatchExpressions []corev1.NodeSelectorRequirement `json:"matchExpressions,omitempty"` +} + +// CPU defines the requirements for the virtual CPU model. +// +kubebuilder:validation:XValidation:rule="self == oldSelf",message=".spec.cpu is immutable" +// +kubebuilder:validation:XValidation:rule="self.type == 'HostPassthrough' || self.type == 'Host' ? !has(self.model) && !has(self.features) && !has(self.discovery) : true",message="HostPassthrough and Host cannot have model, features or discovery" +// +kubebuilder:validation:XValidation:rule="self.type == 'Discovery' ? !has(self.model) && !has(self.features) : true",message="Discovery cannot have model or features" +// +kubebuilder:validation:XValidation:rule="self.type == 'Model' ? has(self.model) && !has(self.features) && !has(self.discovery) : true",message="Model requires model and cannot have features or discovery" +// +kubebuilder:validation:XValidation:rule="self.type == 'Features' ? has(self.features) && !has(self.model) && !has(self.discovery): true",message="Features requires features and cannot have model or discovery" +type CPU struct { + // +kubebuilder:validation:Required + Type CPUType `json:"type"` + // CPU model name. For more information about CPU models and topology, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). + // + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:example=IvyBridge + Model string `json:"model,omitempty"` + // List of CPU instructions (features) required when type=Features. + // For more information about CPU features, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). + // + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:example={mmx, vmx, sse2} + Features []string `json:"features,omitempty"` + // Create a CPU model based on intersecting CPU features for selected nodes. + Discovery *CpuDiscovery `json:"discovery,omitempty"` +} + +type CpuDiscovery struct { + // A selection of nodes to be used as the basis for creating a universal CPU model. + NodeSelector metav1.LabelSelector `json:"nodeSelector,omitempty"` +} + +// SizingPolicy defines a policy for allocating computational resources to VMs. +// It is represented as a list. +// The cores.min - cores.max ranges for different elements of the list must not overlap. +type SizingPolicy struct { + // Memory sizing policy. + Memory *SizingPolicyMemory `json:"memory,omitempty"` + // Allowed values of the `coreFraction` parameter in percentages (e.g., "5%", "10%", "25%", "50%", "100%"). + CoreFractions []CoreFractionValue `json:"coreFractions,omitempty"` + // Allowed values of the `dedicatedCores` parameter. + DedicatedCores []bool `json:"dedicatedCores,omitempty"` + // The policy applies for a specified range of the number of CPU cores. + Cores *SizingPolicyCores `json:"cores,omitempty"` +} + +// CoreFractionValue represents CPU core fraction as a percentage string (e.g., "5%", "10%", "25%", "50%", "100%"). +// +kubebuilder:validation:Pattern=`^([1-9]|[1-9][0-9]|100)%$` +type CoreFractionValue string + +type SizingPolicyMemory struct { + MemoryMinMax `json:",inline"` + // Memory size discretization step. For example, the combination of `min=2Gi, `max=4Gi` and `step=1Gi` allows to set the virtual machine memory size to 2Gi, 3Gi, or 4Gi. + // + // +kubebuilder:example="512Mi" + Step resource.Quantity `json:"step,omitempty"` + + // Amount of memory per CPU core. + PerCore SizingPolicyMemoryPerCore `json:"perCore,omitempty"` +} + +type SizingPolicyMemoryPerCore struct { + MemoryMinMax `json:",inline"` +} + +type MemoryMinMax struct { + // Minimum amount of memory. + // + // +kubebuilder:example="1Gi" + Min resource.Quantity `json:"min,omitempty"` + // Maximum amount of memory. + // + // +kubebuilder:example="8Gi" + Max resource.Quantity `json:"max,omitempty"` +} + +// +kubebuilder:validation:XValidation:rule="self.max > self.min",message="The maximum must be greater than the minimum" +// +kubebuilder:validation:XValidation:rule="has(self.step) ? self.max > self.step : true",message="The maximum must be greater than the step" +type SizingPolicyCores struct { + // Minimum number of CPU cores. + // + // +kubebuilder:validation:Required + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:example=1 + Min int `json:"min"` + // Maximum number of CPU cores. + // + // +kubebuilder:validation:Required + // +kubebuilder:validation:Maximum=1024 + // +kubebuilder:example=10 + Max int `json:"max"` + // Discretization step for the CPU core number. For example, the combination of `min=2`, `max=10`, and `step=4` allows to set the number of virtual machine CPU cores to 2, 6, or 10. + // + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:example=1 + Step int `json:"step,omitempty"` +} + +// CPUType defines the CPU type, the following options are supported: +// * `Host`: Uses a virtual CPU with an instruction set closely matching the platform node's CPU. +// This provides high performance and functionality, as well as compatibility with "live" migration for nodes with similar processor types. +// For example, VM migration between nodes with Intel and AMD processors will not work. +// This is also true for different CPU generations, as their instruction set is different. +// * `HostPassthrough`: Uses the platform node's physical CPU directly, without any modifications. +// When using this class, the guest VM can only be transferred to a target node with a CPU exactly matching the source node's CPU. +// * `Discovery`: Create a virtual CPU based on instruction sets of physical CPUs for a selected set of nodes. +// * `Model`: CPU model. A CPU model is a named and previously defined set of supported CPU instructions. +// * `Features`: A required set of supported instructions for the CPU. +// +// +kubebuilder:validation:Enum={Host,HostPassthrough,Discovery,Model,Features} +type CPUType string + +const ( + CPUTypeHost CPUType = "Host" + CPUTypeHostPassthrough CPUType = "HostPassthrough" + CPUTypeDiscovery CPUType = "Discovery" + CPUTypeModel CPUType = "Model" + CPUTypeFeatures CPUType = "Features" +) + +type VirtualMachineClassStatus struct { + Phase VirtualMachineClassPhase `json:"phase"` + CpuFeatures CpuFeatures `json:"cpuFeatures,omitempty"` + // List of nodes that support this CPU model. + // It is not displayed for the following types: `Host`, `HostPassthrough`. + // + // +kubebuilder:example={node-1, node-2} + AvailableNodes []string `json:"availableNodes,omitempty"` + // Maximum amount of free CPU and memory resources observed among all available nodes. + // +kubebuilder:example={"maxAllocatableResources: {\"cpu\": 1, \"memory\": \"10Gi\"}"} + MaxAllocatableResources corev1.ResourceList `json:"maxAllocatableResources,omitempty"` + // The latest detailed observations of the VirtualMachineClass resource. + Conditions []metav1.Condition `json:"conditions,omitempty"` + // Resource generation last processed by the controller. + ObservedGeneration int64 `json:"observedGeneration,omitempty"` +} + +// CpuFeatures +// Information on CPU features supported by this model. +// Shown only for `Features` or `Discovery` types. +type CpuFeatures struct { + // List of CPU features for this model. + // + // +kubebuilder:example={mmx, vmx, sse2} + Enabled []string `json:"enabled,omitempty"` + // List of unused processor features additionally available for a given group of nodes. + // + // +kubebuilder:example={ssse3, vme} + NotEnabledCommon []string `json:"notEnabledCommon,omitempty"` +} + +// VirtualMachineClassPhase defines the current resource status: +// * `Pending`: The resource is not ready and waits until the suitable nodes supporting the required CPU model are available. +// * `Ready`: The resource is ready and available for use. +// * `Terminating`: The resource is terminating. +// +// +kubebuilder:validation:Enum={Pending,Ready,Terminating} +type VirtualMachineClassPhase string + +const ( + ClassPhasePending VirtualMachineClassPhase = "Pending" + ClassPhaseReady VirtualMachineClassPhase = "Ready" + ClassPhaseTerminating VirtualMachineClassPhase = "Terminating" +) diff --git a/api/core/v1alpha3/virtual_machine_class_conversion.go b/api/core/v1alpha3/virtual_machine_class_conversion.go new file mode 100644 index 0000000000..03a5ba9530 --- /dev/null +++ b/api/core/v1alpha3/virtual_machine_class_conversion.go @@ -0,0 +1,221 @@ +/* +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 v1alpha3 + +import ( + "fmt" + "strconv" + + "sigs.k8s.io/controller-runtime/pkg/conversion" + + "github.com/deckhouse/virtualization/api/core/v1alpha2" +) + +var _ conversion.Convertible = &VirtualMachineClass{} + +func (src *VirtualMachineClass) ConvertTo(dstRaw conversion.Hub) error { + dst := dstRaw.(*v1alpha2.VirtualMachineClass) + + dst.ObjectMeta = src.ObjectMeta + convertedSpec, err := convertSpecV3ToV2(src.Spec) + if err != nil { + return err + } + dst.Spec = convertedSpec + dst.Status = convertStatusV3ToV2(src.Status) + + return nil +} + +func (dst *VirtualMachineClass) ConvertFrom(srcRaw conversion.Hub) error { + src := srcRaw.(*v1alpha2.VirtualMachineClass) + + dst.ObjectMeta = src.ObjectMeta + dst.Spec = convertSpecV2ToV3(src.Spec) + dst.Status = convertStatusV2ToV3(src.Status) + + return nil +} + +func convertSpecV3ToV2(v3Spec VirtualMachineClassSpec) (v1alpha2.VirtualMachineClassSpec, error) { + v2Spec := v1alpha2.VirtualMachineClassSpec{ + NodeSelector: v1alpha2.NodeSelector{ + MatchLabels: v3Spec.NodeSelector.MatchLabels, + MatchExpressions: v3Spec.NodeSelector.MatchExpressions, + }, + Tolerations: v3Spec.Tolerations, + CPU: v1alpha2.CPU{ + Type: v1alpha2.CPUType(v3Spec.CPU.Type), + Model: v3Spec.CPU.Model, + Features: v3Spec.CPU.Features, + }, + } + + if v3Spec.CPU.Discovery != nil { + v2Spec.CPU.Discovery = &v1alpha2.CpuDiscovery{ + NodeSelector: v3Spec.CPU.Discovery.NodeSelector, + } + } + + if len(v3Spec.SizingPolicies) > 0 { + v2Spec.SizingPolicies = make([]v1alpha2.SizingPolicy, len(v3Spec.SizingPolicies)) + for i, v3Policy := range v3Spec.SizingPolicies { + v2Policy := v1alpha2.SizingPolicy{ + DedicatedCores: v3Policy.DedicatedCores, + } + + if v3Policy.Memory != nil { + v2Policy.Memory = &v1alpha2.SizingPolicyMemory{ + MemoryMinMax: v1alpha2.MemoryMinMax{ + Min: v3Policy.Memory.Min, + Max: v3Policy.Memory.Max, + }, + Step: v3Policy.Memory.Step, + PerCore: v1alpha2.SizingPolicyMemoryPerCore{ + MemoryMinMax: v1alpha2.MemoryMinMax{ + Min: v3Policy.Memory.PerCore.Min, + Max: v3Policy.Memory.PerCore.Max, + }, + }, + } + } + + if v3Policy.Cores != nil { + v2Policy.Cores = &v1alpha2.SizingPolicyCores{ + Min: v3Policy.Cores.Min, + Max: v3Policy.Cores.Max, + Step: v3Policy.Cores.Step, + } + } + + if len(v3Policy.CoreFractions) > 0 { + v2Policy.CoreFractions = make([]v1alpha2.CoreFractionValue, len(v3Policy.CoreFractions)) + for j, v3Fraction := range v3Policy.CoreFractions { + fractionStr := string(v3Fraction) + if len(fractionStr) > 0 && fractionStr[len(fractionStr)-1] == '%' { + fractionStr = fractionStr[:len(fractionStr)-1] + } + fractionInt, err := strconv.Atoi(fractionStr) + if err != nil { + return v1alpha2.VirtualMachineClassSpec{}, fmt.Errorf("failed to parse core fraction: %w", err) + } + if fractionInt < 1 || fractionInt > 100 { + return v1alpha2.VirtualMachineClassSpec{}, fmt.Errorf("core fraction value must be between 1 and 100, got %d", fractionInt) + } + v2Policy.CoreFractions[j] = v1alpha2.CoreFractionValue(fractionInt) + } + } + + v2Spec.SizingPolicies[i] = v2Policy + } + } + + return v2Spec, nil +} + +func convertSpecV2ToV3(v2Spec v1alpha2.VirtualMachineClassSpec) VirtualMachineClassSpec { + v3Spec := VirtualMachineClassSpec{ + NodeSelector: NodeSelector{ + MatchLabels: v2Spec.NodeSelector.MatchLabels, + MatchExpressions: v2Spec.NodeSelector.MatchExpressions, + }, + Tolerations: v2Spec.Tolerations, + CPU: CPU{ + Type: CPUType(v2Spec.CPU.Type), + Model: v2Spec.CPU.Model, + Features: v2Spec.CPU.Features, + }, + } + + if v2Spec.CPU.Discovery != nil { + v3Spec.CPU.Discovery = &CpuDiscovery{ + NodeSelector: v2Spec.CPU.Discovery.NodeSelector, + } + } + + if len(v2Spec.SizingPolicies) > 0 { + v3Spec.SizingPolicies = make([]SizingPolicy, len(v2Spec.SizingPolicies)) + for i, v2Policy := range v2Spec.SizingPolicies { + v3Policy := SizingPolicy{ + DedicatedCores: v2Policy.DedicatedCores, + } + + if v2Policy.Memory != nil { + v3Policy.Memory = &SizingPolicyMemory{ + MemoryMinMax: MemoryMinMax{ + Min: v2Policy.Memory.Min, + Max: v2Policy.Memory.Max, + }, + Step: v2Policy.Memory.Step, + PerCore: SizingPolicyMemoryPerCore{ + MemoryMinMax: MemoryMinMax{ + Min: v2Policy.Memory.PerCore.Min, + Max: v2Policy.Memory.PerCore.Max, + }, + }, + } + } + + if v2Policy.Cores != nil { + v3Policy.Cores = &SizingPolicyCores{ + Min: v2Policy.Cores.Min, + Max: v2Policy.Cores.Max, + Step: v2Policy.Cores.Step, + } + } + + if len(v2Policy.CoreFractions) > 0 { + v3Policy.CoreFractions = make([]CoreFractionValue, len(v2Policy.CoreFractions)) + for j, v2Fraction := range v2Policy.CoreFractions { + v3Policy.CoreFractions[j] = CoreFractionValue(fmt.Sprintf("%d%%", v2Fraction)) + } + } + + v3Spec.SizingPolicies[i] = v3Policy + } + } + + return v3Spec +} + +func convertStatusV3ToV2(v3Status VirtualMachineClassStatus) v1alpha2.VirtualMachineClassStatus { + return v1alpha2.VirtualMachineClassStatus{ + Phase: v1alpha2.VirtualMachineClassPhase(v3Status.Phase), + CpuFeatures: v1alpha2.CpuFeatures{ + Enabled: v3Status.CpuFeatures.Enabled, + NotEnabledCommon: v3Status.CpuFeatures.NotEnabledCommon, + }, + AvailableNodes: v3Status.AvailableNodes, + MaxAllocatableResources: v3Status.MaxAllocatableResources, + Conditions: v3Status.Conditions, + ObservedGeneration: v3Status.ObservedGeneration, + } +} + +func convertStatusV2ToV3(v2Status v1alpha2.VirtualMachineClassStatus) VirtualMachineClassStatus { + return VirtualMachineClassStatus{ + Phase: VirtualMachineClassPhase(v2Status.Phase), + CpuFeatures: CpuFeatures{ + Enabled: v2Status.CpuFeatures.Enabled, + NotEnabledCommon: v2Status.CpuFeatures.NotEnabledCommon, + }, + AvailableNodes: v2Status.AvailableNodes, + MaxAllocatableResources: v2Status.MaxAllocatableResources, + Conditions: v2Status.Conditions, + ObservedGeneration: v2Status.ObservedGeneration, + } +} diff --git a/api/core/v1alpha3/virtual_machine_class_conversion_test.go b/api/core/v1alpha3/virtual_machine_class_conversion_test.go new file mode 100644 index 0000000000..d267178277 --- /dev/null +++ b/api/core/v1alpha3/virtual_machine_class_conversion_test.go @@ -0,0 +1,399 @@ +/* +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 v1alpha3 + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/deckhouse/virtualization/api/core/v1alpha2" +) + +var _ = Describe("VirtualMachineClass Conversion", func() { + Context("ConvertTo v1alpha2", func() { + DescribeTable("should convert valid CoreFractionValue strings", + func(coreFractions []CoreFractionValue) { + v3Class := &VirtualMachineClass{ + ObjectMeta: metav1.ObjectMeta{Name: "test-class"}, + Spec: VirtualMachineClassSpec{ + SizingPolicies: []SizingPolicy{ + { + CoreFractions: coreFractions, + Cores: &SizingPolicyCores{ + Min: 1, + Max: 8, + Step: 1, + }, + }, + }, + }, + } + + v2Class := &v1alpha2.VirtualMachineClass{} + err := v3Class.ConvertTo(v2Class) + + Expect(err).NotTo(HaveOccurred()) + Expect(v2Class.Name).To(Equal(v3Class.Name)) + Expect(v2Class.Spec.SizingPolicies).To(HaveLen(1)) + Expect(v2Class.Spec.SizingPolicies[0].CoreFractions).To(HaveLen(len(coreFractions))) + }, + Entry("single value", []CoreFractionValue{"5%"}), + Entry("multiple values", []CoreFractionValue{"5%", "10%", "25%", "50%", "100%"}), + Entry("minimum value 1%", []CoreFractionValue{"1%"}), + Entry("maximum value 100%", []CoreFractionValue{"100%"}), + Entry("mixed valid values", []CoreFractionValue{"1%", "50%", "100%"}), + Entry("value without percent sign", []CoreFractionValue{"50"}), + ) + + DescribeTable("should fail on invalid CoreFractionValue strings", + func(coreFractions []CoreFractionValue, expectedErrorSubstring string) { + v3Class := &VirtualMachineClass{ + ObjectMeta: metav1.ObjectMeta{Name: "test-class"}, + Spec: VirtualMachineClassSpec{ + SizingPolicies: []SizingPolicy{ + { + CoreFractions: coreFractions, + Cores: &SizingPolicyCores{ + Min: 1, + Max: 4, + Step: 1, + }, + }, + }, + }, + } + + v2Class := &v1alpha2.VirtualMachineClass{} + err := v3Class.ConvertTo(v2Class) + + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring(expectedErrorSubstring)) + }, + Entry("value below minimum (0%)", []CoreFractionValue{"0%"}, "must be between 1 and 100, got 0"), + Entry("value above maximum (101%)", []CoreFractionValue{"101%"}, "must be between 1 and 100, got 101"), + Entry("negative value", []CoreFractionValue{"-5%"}, "must be between 1 and 100, got -5"), + Entry("non-numeric value", []CoreFractionValue{"abc%"}, "failed to parse core fraction"), + Entry("empty string", []CoreFractionValue{""}, "failed to parse core fraction"), + Entry("percent sign in wrong position", []CoreFractionValue{"%50"}, "failed to parse core fraction"), + Entry("one invalid in multiple", []CoreFractionValue{"5%", "150%", "100%"}, "must be between 1 and 100, got 150"), + ) + + It("should preserve ObjectMeta", func() { + v3Class := &VirtualMachineClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-class", + Namespace: "test-ns", + Labels: map[string]string{ + "test-label": "test-value", + }, + }, + Spec: VirtualMachineClassSpec{}, + } + + v2Class := &v1alpha2.VirtualMachineClass{} + err := v3Class.ConvertTo(v2Class) + + Expect(err).NotTo(HaveOccurred()) + Expect(v2Class.Name).To(Equal("test-class")) + Expect(v2Class.Namespace).To(Equal("test-ns")) + Expect(v2Class.Labels).To(HaveKeyWithValue("test-label", "test-value")) + }) + }) + + Context("ConvertFrom v1alpha2", func() { + DescribeTable("should convert v1alpha2 CoreFractionValue integers to percentage strings", + func(v2CoreFractions []v1alpha2.CoreFractionValue, expectedV3Values []CoreFractionValue) { + v2Class := &v1alpha2.VirtualMachineClass{ + ObjectMeta: metav1.ObjectMeta{Name: "test-class"}, + Spec: v1alpha2.VirtualMachineClassSpec{ + SizingPolicies: []v1alpha2.SizingPolicy{ + { + CoreFractions: v2CoreFractions, + Cores: &v1alpha2.SizingPolicyCores{ + Min: 1, + Max: 8, + Step: 1, + }, + }, + }, + }, + } + + v3Class := &VirtualMachineClass{} + err := v3Class.ConvertFrom(v2Class) + + Expect(err).NotTo(HaveOccurred()) + Expect(v3Class.Spec.SizingPolicies).To(HaveLen(1)) + Expect(v3Class.Spec.SizingPolicies[0].CoreFractions).To(Equal(expectedV3Values)) + }, + Entry("single value", []v1alpha2.CoreFractionValue{5}, []CoreFractionValue{"5%"}), + Entry("multiple values", []v1alpha2.CoreFractionValue{5, 10, 25, 50, 100}, []CoreFractionValue{"5%", "10%", "25%", "50%", "100%"}), + Entry("minimum value", []v1alpha2.CoreFractionValue{1}, []CoreFractionValue{"1%"}), + Entry("maximum value", []v1alpha2.CoreFractionValue{100}, []CoreFractionValue{"100%"}), + ) + }) + + Context("Round-trip conversion", func() { + DescribeTable("should preserve values through v2 -> v3 -> v2 conversion", + func(v2CoreFractions []v1alpha2.CoreFractionValue) { + originalV2 := &v1alpha2.VirtualMachineClass{ + ObjectMeta: metav1.ObjectMeta{Name: "test-class"}, + Spec: v1alpha2.VirtualMachineClassSpec{ + SizingPolicies: []v1alpha2.SizingPolicy{ + { + CoreFractions: v2CoreFractions, + Cores: &v1alpha2.SizingPolicyCores{ + Min: 1, + Max: 8, + Step: 1, + }, + }, + }, + }, + } + + v3Class := &VirtualMachineClass{} + err := v3Class.ConvertFrom(originalV2) + Expect(err).NotTo(HaveOccurred()) + + roundTripV2 := &v1alpha2.VirtualMachineClass{} + err = v3Class.ConvertTo(roundTripV2) + Expect(err).NotTo(HaveOccurred()) + + Expect(roundTripV2.Spec.SizingPolicies).To(HaveLen(1)) + Expect(roundTripV2.Spec.SizingPolicies[0].CoreFractions).To(Equal(v2CoreFractions)) + }, + Entry("single value", []v1alpha2.CoreFractionValue{5}), + Entry("multiple values", []v1alpha2.CoreFractionValue{5, 10, 25, 50, 100}), + Entry("boundary values", []v1alpha2.CoreFractionValue{1, 100}), + ) + }) + + Context("Full spec conversion", func() { + var ( + minMem, maxMem, stepMem resource.Quantity + minPerCoreMem, maxPerCoreMem resource.Quantity + ) + + BeforeEach(func() { + minMem = resource.MustParse("1Gi") + maxMem = resource.MustParse("8Gi") + stepMem = resource.MustParse("1Gi") + minPerCoreMem = resource.MustParse("512Mi") + maxPerCoreMem = resource.MustParse("2Gi") + }) + + It("should preserve all fields in ConvertTo", func() { + v3Class := &VirtualMachineClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "full-test-class", + Namespace: "test-namespace", + Labels: map[string]string{ + "test-label": "test-value", + }, + Annotations: map[string]string{ + "test-annotation": "test-value", + }, + }, + Spec: VirtualMachineClassSpec{ + NodeSelector: NodeSelector{ + MatchLabels: map[string]string{ + "node-role": "worker", + "zone": "us-east-1a", + }, + MatchExpressions: []corev1.NodeSelectorRequirement{ + { + Key: "cpu-type", + Operator: corev1.NodeSelectorOpIn, + Values: []string{"intel", "amd"}, + }, + }, + }, + Tolerations: []corev1.Toleration{ + { + Key: "dedicated", + Operator: corev1.TolerationOpEqual, + Value: "virtualization", + Effect: corev1.TaintEffectNoSchedule, + }, + }, + CPU: CPU{ + Type: CPUTypeModel, + Model: "IvyBridge", + Features: nil, + Discovery: nil, + }, + SizingPolicies: []SizingPolicy{ + { + Memory: &SizingPolicyMemory{ + MemoryMinMax: MemoryMinMax{ + Min: minMem, + Max: maxMem, + }, + Step: stepMem, + PerCore: SizingPolicyMemoryPerCore{ + MemoryMinMax: MemoryMinMax{ + Min: minPerCoreMem, + Max: maxPerCoreMem, + }, + }, + }, + CoreFractions: []CoreFractionValue{"5%", "10%", "50%", "100%"}, + DedicatedCores: []bool{false, true}, + Cores: &SizingPolicyCores{ + Min: 1, + Max: 16, + Step: 2, + }, + }, + }, + }, + } + + v2Class := &v1alpha2.VirtualMachineClass{} + err := v3Class.ConvertTo(v2Class) + Expect(err).NotTo(HaveOccurred()) + + Expect(v2Class.Name).To(Equal("full-test-class")) + Expect(v2Class.Namespace).To(Equal("test-namespace")) + Expect(v2Class.Labels).To(HaveKeyWithValue("test-label", "test-value")) + Expect(v2Class.Annotations).To(HaveKeyWithValue("test-annotation", "test-value")) + + Expect(v2Class.Spec.NodeSelector.MatchLabels).To(Equal(map[string]string{ + "node-role": "worker", + "zone": "us-east-1a", + })) + Expect(v2Class.Spec.NodeSelector.MatchExpressions).To(HaveLen(1)) + Expect(v2Class.Spec.NodeSelector.MatchExpressions[0].Key).To(Equal("cpu-type")) + + Expect(v2Class.Spec.Tolerations).To(HaveLen(1)) + Expect(v2Class.Spec.Tolerations[0].Key).To(Equal("dedicated")) + Expect(v2Class.Spec.Tolerations[0].Value).To(Equal("virtualization")) + + Expect(string(v2Class.Spec.CPU.Type)).To(Equal("Model")) + Expect(v2Class.Spec.CPU.Model).To(Equal("IvyBridge")) + + Expect(v2Class.Spec.SizingPolicies).To(HaveLen(1)) + policy := v2Class.Spec.SizingPolicies[0] + + Expect(policy.Memory).NotTo(BeNil()) + Expect(policy.Memory.Min.Equal(minMem)).To(BeTrue()) + Expect(policy.Memory.Max.Equal(maxMem)).To(BeTrue()) + Expect(policy.Memory.Step.Equal(stepMem)).To(BeTrue()) + Expect(policy.Memory.PerCore.Min.Equal(minPerCoreMem)).To(BeTrue()) + Expect(policy.Memory.PerCore.Max.Equal(maxPerCoreMem)).To(BeTrue()) + + Expect(policy.CoreFractions).To(Equal([]v1alpha2.CoreFractionValue{5, 10, 50, 100})) + Expect(policy.DedicatedCores).To(Equal([]bool{false, true})) + + Expect(policy.Cores).NotTo(BeNil()) + Expect(policy.Cores.Min).To(Equal(1)) + Expect(policy.Cores.Max).To(Equal(16)) + Expect(policy.Cores.Step).To(Equal(2)) + }) + + It("should preserve all fields in ConvertFrom", func() { + v2Class := &v1alpha2.VirtualMachineClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "full-test-class", + Namespace: "test-namespace", + Labels: map[string]string{ + "test-label": "test-value", + }, + }, + Spec: v1alpha2.VirtualMachineClassSpec{ + NodeSelector: v1alpha2.NodeSelector{ + MatchLabels: map[string]string{ + "node-role": "worker", + }, + }, + Tolerations: []corev1.Toleration{ + { + Key: "dedicated", + Operator: corev1.TolerationOpEqual, + Value: "virtualization", + Effect: corev1.TaintEffectNoSchedule, + }, + }, + CPU: v1alpha2.CPU{ + Type: v1alpha2.CPUTypeFeatures, + Features: []string{"mmx", "sse2", "vmx"}, + }, + SizingPolicies: []v1alpha2.SizingPolicy{ + { + Memory: &v1alpha2.SizingPolicyMemory{ + MemoryMinMax: v1alpha2.MemoryMinMax{ + Min: minMem, + Max: maxMem, + }, + Step: stepMem, + PerCore: v1alpha2.SizingPolicyMemoryPerCore{ + MemoryMinMax: v1alpha2.MemoryMinMax{ + Min: minPerCoreMem, + Max: maxPerCoreMem, + }, + }, + }, + CoreFractions: []v1alpha2.CoreFractionValue{10, 50, 100}, + DedicatedCores: []bool{true}, + Cores: &v1alpha2.SizingPolicyCores{ + Min: 2, + Max: 8, + Step: 2, + }, + }, + }, + }, + } + + v3Class := &VirtualMachineClass{} + err := v3Class.ConvertFrom(v2Class) + Expect(err).NotTo(HaveOccurred()) + + Expect(v3Class.Name).To(Equal("full-test-class")) + Expect(v3Class.Namespace).To(Equal("test-namespace")) + Expect(v3Class.Labels).To(HaveKeyWithValue("test-label", "test-value")) + + Expect(v3Class.Spec.NodeSelector.MatchLabels).To(HaveKeyWithValue("node-role", "worker")) + + Expect(v3Class.Spec.Tolerations).To(HaveLen(1)) + Expect(v3Class.Spec.Tolerations[0].Key).To(Equal("dedicated")) + + Expect(string(v3Class.Spec.CPU.Type)).To(Equal("Features")) + Expect(v3Class.Spec.CPU.Features).To(Equal([]string{"mmx", "sse2", "vmx"})) + + Expect(v3Class.Spec.SizingPolicies).To(HaveLen(1)) + policy := v3Class.Spec.SizingPolicies[0] + + Expect(policy.Memory).NotTo(BeNil()) + Expect(policy.Memory.Min.Equal(minMem)).To(BeTrue()) + Expect(policy.Memory.Max.Equal(maxMem)).To(BeTrue()) + Expect(policy.Memory.Step.Equal(stepMem)).To(BeTrue()) + + Expect(policy.CoreFractions).To(Equal([]CoreFractionValue{"10%", "50%", "100%"})) + Expect(policy.DedicatedCores).To(Equal([]bool{true})) + + Expect(policy.Cores).NotTo(BeNil()) + Expect(policy.Cores.Min).To(Equal(2)) + Expect(policy.Cores.Max).To(Equal(8)) + Expect(policy.Cores.Step).To(Equal(2)) + }) + }) +}) diff --git a/api/core/v1alpha3/vmclasscondition/condition.go b/api/core/v1alpha3/vmclasscondition/condition.go new file mode 100644 index 0000000000..8790297ff9 --- /dev/null +++ b/api/core/v1alpha3/vmclasscondition/condition.go @@ -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 vmclasscondition + +type Type string + +func (t Type) String() string { + return string(t) +} + +const ( + TypeReady Type = "Ready" + TypeDiscovered Type = "Discovered" + TypeInUse Type = "InUse" +) + +type Reason string + +func (r Reason) String() string { + return string(r) +} + +const ( + // ReasonNoCpuFeaturesEnabled determines that processor functions are not available. + ReasonNoCpuFeaturesEnabled Reason = "NoCpuFeaturesEnabled" + // ReasonNoSuitableNodesFound determines that no suitable node has been found. + ReasonNoSuitableNodesFound Reason = "NoSuitableNodesFound" + // ReasonSuitableNodesFound determines that suitable node has been found. + ReasonSuitableNodesFound Reason = "SuitableNodesFound" + + ReasonDiscoverySucceeded Reason = "DiscoverySucceeded" + ReasonDiscoverySkip Reason = "DiscoverySkip" + ReasonDiscoveryFailed Reason = "DiscoveryFailed" + + // ReasonVMClassInUse is the event reason indicating that the VMClass is being used by a virtual machine. + ReasonVMClassInUse Reason = "VirtualMachineClassInUse" +) diff --git a/api/core/v1alpha3/zz_generated.deepcopy.go b/api/core/v1alpha3/zz_generated.deepcopy.go new file mode 100644 index 0000000000..7034c5d025 --- /dev/null +++ b/api/core/v1alpha3/zz_generated.deepcopy.go @@ -0,0 +1,362 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CPU) DeepCopyInto(out *CPU) { + *out = *in + if in.Features != nil { + in, out := &in.Features, &out.Features + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Discovery != nil { + in, out := &in.Discovery, &out.Discovery + *out = new(CpuDiscovery) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CPU. +func (in *CPU) DeepCopy() *CPU { + if in == nil { + return nil + } + out := new(CPU) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CpuDiscovery) DeepCopyInto(out *CpuDiscovery) { + *out = *in + in.NodeSelector.DeepCopyInto(&out.NodeSelector) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CpuDiscovery. +func (in *CpuDiscovery) DeepCopy() *CpuDiscovery { + if in == nil { + return nil + } + out := new(CpuDiscovery) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CpuFeatures) DeepCopyInto(out *CpuFeatures) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.NotEnabledCommon != nil { + in, out := &in.NotEnabledCommon, &out.NotEnabledCommon + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CpuFeatures. +func (in *CpuFeatures) DeepCopy() *CpuFeatures { + if in == nil { + return nil + } + out := new(CpuFeatures) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MemoryMinMax) DeepCopyInto(out *MemoryMinMax) { + *out = *in + out.Min = in.Min.DeepCopy() + out.Max = in.Max.DeepCopy() + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MemoryMinMax. +func (in *MemoryMinMax) DeepCopy() *MemoryMinMax { + if in == nil { + return nil + } + out := new(MemoryMinMax) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeSelector) DeepCopyInto(out *NodeSelector) { + *out = *in + if in.MatchLabels != nil { + in, out := &in.MatchLabels, &out.MatchLabels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.MatchExpressions != nil { + in, out := &in.MatchExpressions, &out.MatchExpressions + *out = make([]v1.NodeSelectorRequirement, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeSelector. +func (in *NodeSelector) DeepCopy() *NodeSelector { + if in == nil { + return nil + } + out := new(NodeSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SizingPolicy) DeepCopyInto(out *SizingPolicy) { + *out = *in + if in.Memory != nil { + in, out := &in.Memory, &out.Memory + *out = new(SizingPolicyMemory) + (*in).DeepCopyInto(*out) + } + if in.CoreFractions != nil { + in, out := &in.CoreFractions, &out.CoreFractions + *out = make([]CoreFractionValue, len(*in)) + copy(*out, *in) + } + if in.DedicatedCores != nil { + in, out := &in.DedicatedCores, &out.DedicatedCores + *out = make([]bool, len(*in)) + copy(*out, *in) + } + if in.Cores != nil { + in, out := &in.Cores, &out.Cores + *out = new(SizingPolicyCores) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SizingPolicy. +func (in *SizingPolicy) DeepCopy() *SizingPolicy { + if in == nil { + return nil + } + out := new(SizingPolicy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SizingPolicyCores) DeepCopyInto(out *SizingPolicyCores) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SizingPolicyCores. +func (in *SizingPolicyCores) DeepCopy() *SizingPolicyCores { + if in == nil { + return nil + } + out := new(SizingPolicyCores) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SizingPolicyMemory) DeepCopyInto(out *SizingPolicyMemory) { + *out = *in + in.MemoryMinMax.DeepCopyInto(&out.MemoryMinMax) + out.Step = in.Step.DeepCopy() + in.PerCore.DeepCopyInto(&out.PerCore) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SizingPolicyMemory. +func (in *SizingPolicyMemory) DeepCopy() *SizingPolicyMemory { + if in == nil { + return nil + } + out := new(SizingPolicyMemory) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SizingPolicyMemoryPerCore) DeepCopyInto(out *SizingPolicyMemoryPerCore) { + *out = *in + in.MemoryMinMax.DeepCopyInto(&out.MemoryMinMax) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SizingPolicyMemoryPerCore. +func (in *SizingPolicyMemoryPerCore) DeepCopy() *SizingPolicyMemoryPerCore { + if in == nil { + return nil + } + out := new(SizingPolicyMemoryPerCore) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtualMachineClass) DeepCopyInto(out *VirtualMachineClass) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualMachineClass. +func (in *VirtualMachineClass) DeepCopy() *VirtualMachineClass { + if in == nil { + return nil + } + out := new(VirtualMachineClass) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VirtualMachineClass) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtualMachineClassList) DeepCopyInto(out *VirtualMachineClassList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]VirtualMachineClass, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualMachineClassList. +func (in *VirtualMachineClassList) DeepCopy() *VirtualMachineClassList { + if in == nil { + return nil + } + out := new(VirtualMachineClassList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VirtualMachineClassList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtualMachineClassSpec) DeepCopyInto(out *VirtualMachineClassSpec) { + *out = *in + in.NodeSelector.DeepCopyInto(&out.NodeSelector) + if in.Tolerations != nil { + in, out := &in.Tolerations, &out.Tolerations + *out = make([]v1.Toleration, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.CPU.DeepCopyInto(&out.CPU) + if in.SizingPolicies != nil { + in, out := &in.SizingPolicies, &out.SizingPolicies + *out = make([]SizingPolicy, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualMachineClassSpec. +func (in *VirtualMachineClassSpec) DeepCopy() *VirtualMachineClassSpec { + if in == nil { + return nil + } + out := new(VirtualMachineClassSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtualMachineClassStatus) DeepCopyInto(out *VirtualMachineClassStatus) { + *out = *in + in.CpuFeatures.DeepCopyInto(&out.CpuFeatures) + if in.AvailableNodes != nil { + in, out := &in.AvailableNodes, &out.AvailableNodes + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.MaxAllocatableResources != nil { + in, out := &in.MaxAllocatableResources, &out.MaxAllocatableResources + *out = make(v1.ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualMachineClassStatus. +func (in *VirtualMachineClassStatus) DeepCopy() *VirtualMachineClassStatus { + if in == nil { + return nil + } + out := new(VirtualMachineClassStatus) + in.DeepCopyInto(out) + return out +} diff --git a/api/go.mod b/api/go.mod index 0aece635b3..f64524d560 100644 --- a/api/go.mod +++ b/api/go.mod @@ -10,13 +10,15 @@ tool ( require ( github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 + github.com/onsi/ginkgo/v2 v2.22.0 + github.com/onsi/gomega v1.36.1 github.com/spf13/pflag v1.0.7 k8s.io/api v0.33.3 k8s.io/apiextensions-apiserver v0.33.3 k8s.io/apimachinery v0.33.3 k8s.io/client-go v0.33.3 - k8s.io/kube-openapi v0.0.0-20250701173324-9bd5c66d9911 kubevirt.io/api v1.3.1 + sigs.k8s.io/controller-runtime v0.21.0 ) require ( @@ -28,10 +30,12 @@ require ( github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gobuffalo/flect v1.0.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect + github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/uuid v1.6.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -66,10 +70,11 @@ require ( k8s.io/code-generator v0.33.3 // indirect k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f // indirect k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20250701173324-9bd5c66d9911 // indirect k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 // indirect kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 // indirect - sigs.k8s.io/controller-tools v0.18.0 // indirect + sigs.k8s.io/controller-tools v0.16.5 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect diff --git a/api/go.sum b/api/go.sum index 8bb4a2fd8b..ec3dce0a5a 100644 --- a/api/go.sum +++ b/api/go.sum @@ -62,7 +62,6 @@ github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+ github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= @@ -104,8 +103,8 @@ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -184,8 +183,8 @@ github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xl github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= -github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= +github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= @@ -207,8 +206,8 @@ github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3ev github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= -github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= -github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= +github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw= +github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= github.com/openshift/api v0.0.0-20230503133300-8bbcb7ca7183 h1:t/CahSnpqY46sQR01SoS+Jt0jtjgmhgE6lFmRnO4q70= github.com/openshift/api v0.0.0-20230503133300-8bbcb7ca7183/go.mod h1:4VWG+W22wrB4HfBL88P40DxLEpSOaiBVxUnfalfJo9k= github.com/openshift/custom-resource-status v1.1.2 h1:C3DL44LEbvlbItfd8mT5jWrqPfHnSOQoQf/sypqA6A4= @@ -575,8 +574,10 @@ kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 h1:IWo12+ei3jltSN5jQN kubevirt.io/containerized-data-importer-api v1.57.0-alpha1/go.mod h1:Y/8ETgHS1GjO89bl682DPtQOYEU/1ctPFBz6Sjxm4DM= kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 h1:QMrd0nKP0BGbnxTqakhDZAUhGKxPiPiN5gSDqKUmGGc= kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90/go.mod h1:018lASpFYBsYN6XwmA2TIrPCx6e0gviTd/ZNtSitKgc= -sigs.k8s.io/controller-tools v0.18.0 h1:rGxGZCZTV2wJreeRgqVoWab/mfcumTMmSwKzoM9xrsE= -sigs.k8s.io/controller-tools v0.18.0/go.mod h1:gLKoiGBriyNh+x1rWtUQnakUYEujErjXs9pf+x/8n1U= +sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8= +sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM= +sigs.k8s.io/controller-tools v0.16.5 h1:5k9FNRqziBPwqr17AMEPPV/En39ZBplLAdOwwQHruP4= +sigs.k8s.io/controller-tools v0.16.5/go.mod h1:8vztuRVzs8IuuJqKqbXCSlXcw+lkAv/M2sTpg55qjMY= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= diff --git a/api/scripts/update-codegen.sh b/api/scripts/update-codegen.sh index 759cacea8f..9c6e7d6502 100755 --- a/api/scripts/update-codegen.sh +++ b/api/scripts/update-codegen.sh @@ -55,7 +55,7 @@ function generate::subresources { --output-file "zz_generated.openapi.go" \ --go-header-file "${SCRIPT_DIR}/boilerplate.go.txt" \ -r /dev/null \ - "${THIS_PKG}/core/v1alpha2" "${THIS_PKG}/subresources/v1alpha2" "kubevirt.io/api/core/v1" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/version" + "${THIS_PKG}/core/v1alpha2" "${THIS_PKG}/core/v1alpha3" "${THIS_PKG}/subresources/v1alpha2" "kubevirt.io/api/core/v1" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/version" } function generate::core { @@ -75,7 +75,7 @@ function generate::crds { OUTPUT_BASE=$(mktemp -d) trap 'rm -rf "${OUTPUT_BASE}"' ERR EXIT - go tool controller-gen crd paths="${API_ROOT}/core/v1alpha2/..." output:crd:dir="${OUTPUT_BASE}" + go tool controller-gen crd:crdVersions=v1 paths="${API_ROOT}/core/v1alpha2/...;${API_ROOT}/core/v1alpha3/..." output:crd:dir="${OUTPUT_BASE}" # shellcheck disable=SC2044 for file in $(find "${OUTPUT_BASE}"/* -type f -iname "*.yaml"); do diff --git a/crds/doc-ru-virtualmachineclasses.yaml b/crds/doc-ru-virtualmachineclasses.yaml index fd11d51e4f..c0abe39ad8 100644 --- a/crds/doc-ru-virtualmachineclasses.yaml +++ b/crds/doc-ru-virtualmachineclasses.yaml @@ -133,7 +133,7 @@ spec: properties: coreFractions: description: | - Допустимые значения параметра `coreFraction`. + Допустимые значения параметра `coreFraction` в процентах (например, "5%", "10%", "25%", "50%", "100%"). cores: description: | Политика применяется для заданного диапазона числа ядер CPU. diff --git a/crds/virtualmachineclasses.yaml b/crds/virtualmachineclasses.yaml index c3fdfa794a..11741dddd3 100644 --- a/crds/virtualmachineclasses.yaml +++ b/crds/virtualmachineclasses.yaml @@ -513,3 +513,498 @@ spec: storage: true subresources: status: {} + - additionalPrinterColumns: + - description: VirtualMachineClass phase. + jsonPath: .status.phase + name: Phase + type: string + - description: Default class for virtual machines without specified class. + jsonPath: .metadata.annotations.virtualmachineclass\.virtualization\.deckhouse\.io\/is-default-class + name: IsDefault + type: string + - description: Time of resource creation. + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha3 + schema: + openAPIV3Schema: + description: |- + VirtualMachineClass resource describes CPU requirements, node placement, and sizing policy for VM resources. + A resource cannot be deleted as long as it is used in one of the VMs. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + cpu: + description: CPU defines the requirements for the virtual CPU model. + properties: + discovery: + description: + Create a CPU model based on intersecting CPU features + for selected nodes. + properties: + nodeSelector: + description: + A selection of nodes to be used as the basis + for creating a universal CPU model. + properties: + matchExpressions: + description: + matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: + key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + features: + description: |- + List of CPU instructions (features) required when type=Features. + For more information about CPU features, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). + example: + - mmx + - vmx + - sse2 + items: + type: string + minItems: 1 + type: array + model: + description: + CPU model name. For more information about CPU models + and topology, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology). + example: IvyBridge + minLength: 1 + type: string + type: + description: |- + CPUType defines the CPU type, the following options are supported: + * `Host`: Uses a virtual CPU with an instruction set closely matching the platform node's CPU. + This provides high performance and functionality, as well as compatibility with "live" migration for nodes with similar processor types. + For example, VM migration between nodes with Intel and AMD processors will not work. + This is also true for different CPU generations, as their instruction set is different. + * `HostPassthrough`: Uses the platform node's physical CPU directly, without any modifications. + When using this class, the guest VM can only be transferred to a target node with a CPU exactly matching the source node's CPU. + * `Discovery`: Create a virtual CPU based on instruction sets of physical CPUs for a selected set of nodes. + * `Model`: CPU model. A CPU model is a named and previously defined set of supported CPU instructions. + * `Features`: A required set of supported instructions for the CPU. + enum: + - Host + - HostPassthrough + - Discovery + - Model + - Features + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: .spec.cpu is immutable + rule: self == oldSelf + - message: + HostPassthrough and Host cannot have model, features or + discovery + rule: + "self.type == 'HostPassthrough' || self.type == 'Host' + ? !has(self.model) && !has(self.features) && !has(self.discovery) + : true" + - message: Discovery cannot have model or features + rule: + "self.type == 'Discovery' ? !has(self.model) && !has(self.features) + : true" + - message: Model requires model and cannot have features or discovery + rule: + "self.type == 'Model' ? has(self.model) && !has(self.features) + && !has(self.discovery) : true" + - message: Features requires features and cannot have model or discovery + rule: + "self.type == 'Features' ? has(self.features) && !has(self.model) + && !has(self.discovery): true" + nodeSelector: + description: NodeSelector defines the nodes targeted for VM scheduling. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + A map of {key,value} pairs. + A single {key,value} pair in the matchLabels map is equivalent to an element of matchExpressions whose key field is "key", operator is "In", and the value array contains only "value". + The requirements are ANDed. + type: object + type: object + sizingPolicies: + items: + description: |- + SizingPolicy defines a policy for allocating computational resources to VMs. + It is represented as a list. + The cores.min - cores.max ranges for different elements of the list must not overlap. + properties: + coreFractions: + description: + Allowed values of the `coreFraction` parameter + in percentages (e.g., "5%", "10%", "25%", "50%", "100%"). + items: + description: + CoreFractionValue represents CPU core fraction + as a percentage string (e.g., "5%", "10%", "25%", "50%", + "100%"). + pattern: ^([1-9]|[1-9][0-9]|100)%$ + type: string + type: array + cores: + description: + The policy applies for a specified range of the + number of CPU cores. + properties: + max: + description: Maximum number of CPU cores. + example: 10 + maximum: 1024 + type: integer + min: + description: Minimum number of CPU cores. + example: 1 + minimum: 1 + type: integer + step: + description: + Discretization step for the CPU core number. + For example, the combination of `min=2`, `max=10`, and + `step=4` allows to set the number of virtual machine CPU + cores to 2, 6, or 10. + example: 1 + minimum: 1 + type: integer + required: + - max + - min + type: object + x-kubernetes-validations: + - message: The maximum must be greater than the minimum + rule: self.max > self.min + - message: The maximum must be greater than the step + rule: "has(self.step) ? self.max > self.step : true" + dedicatedCores: + description: Allowed values of the `dedicatedCores` parameter. + items: + type: boolean + type: array + memory: + description: Memory sizing policy. + properties: + max: + anyOf: + - type: integer + - type: string + description: Maximum amount of memory. + example: 8Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + min: + anyOf: + - type: integer + - type: string + description: Minimum amount of memory. + example: 1Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + perCore: + description: Amount of memory per CPU core. + properties: + max: + anyOf: + - type: integer + - type: string + description: Maximum amount of memory. + example: 8Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + min: + anyOf: + - type: integer + - type: string + description: Minimum amount of memory. + example: 1Gi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + step: + anyOf: + - type: integer + - type: string + description: + Memory size discretization step. For example, + the combination of `min=2Gi, `max=4Gi` and `step=1Gi` + allows to set the virtual machine memory size to 2Gi, + 3Gi, or 4Gi. + example: 512Mi + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + type: array + tolerations: + description: |- + Tolerations are the same as `spec.tolerations` for [pods](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/). + These tolerations will be merged with the tolerations specified in the VirtualMachine resource. VirtualMachine tolerations have a higher priority. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + required: + - cpu + type: object + status: + properties: + availableNodes: + description: |- + List of nodes that support this CPU model. + It is not displayed for the following types: `Host`, `HostPassthrough`. + example: + - node-1 + - node-2 + items: + type: string + type: array + conditions: + description: + The latest detailed observations of the VirtualMachineClass + resource. + items: + description: + Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + cpuFeatures: + description: |- + CpuFeatures + Information on CPU features supported by this model. + Shown only for `Features` or `Discovery` types. + properties: + enabled: + description: " List of CPU features for this model." + example: + - mmx + - vmx + - sse2 + items: + type: string + type: array + notEnabledCommon: + description: + List of unused processor features additionally available + for a given group of nodes. + example: + - ssse3 + - vme + items: + type: string + type: array + type: object + maxAllocatableResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: + Maximum amount of free CPU and memory resources observed + among all available nodes. + example: + - 'maxAllocatableResources: {"cpu": 1, "memory": "10Gi"}' + type: object + observedGeneration: + description: Resource generation last processed by the controller. + format: int64 + type: integer + phase: + description: |- + VirtualMachineClassPhase defines the current resource status: + * `Pending`: The resource is not ready and waits until the suitable nodes supporting the required CPU model are available. + * `Ready`: The resource is ready and available for use. + * `Terminating`: The resource is terminating. + enum: + - Pending + - Ready + - Terminating + type: string + required: + - phase + type: object + required: + - spec + type: object + served: true + storage: false + subresources: + status: {} diff --git a/images/hooks/go.mod b/images/hooks/go.mod index 027e9646b4..0f65b8ba81 100644 --- a/images/hooks/go.mod +++ b/images/hooks/go.mod @@ -47,7 +47,7 @@ require ( github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-containerregistry v0.17.0 // indirect - github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect + github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/uuid v1.6.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmoiron/sqlx v1.3.5 // indirect diff --git a/images/hooks/go.sum b/images/hooks/go.sum index d39e4d9de0..0fa95aed83 100644 --- a/images/hooks/go.sum +++ b/images/hooks/go.sum @@ -147,8 +147,9 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= diff --git a/images/virtualization-artifact/cmd/virtualization-controller/main.go b/images/virtualization-artifact/cmd/virtualization-controller/main.go index f4b0f9d26a..eb12610303 100644 --- a/images/virtualization-artifact/cmd/virtualization-controller/main.go +++ b/images/virtualization-artifact/cmd/virtualization-controller/main.go @@ -61,12 +61,14 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/controller/vmsnapshot" "github.com/deckhouse/virtualization-controller/pkg/controller/volumemigration" workloadupdater "github.com/deckhouse/virtualization-controller/pkg/controller/workload-updater" + "github.com/deckhouse/virtualization-controller/pkg/crd" "github.com/deckhouse/virtualization-controller/pkg/featuregates" "github.com/deckhouse/virtualization-controller/pkg/logger" "github.com/deckhouse/virtualization-controller/pkg/migration" "github.com/deckhouse/virtualization-controller/pkg/version" "github.com/deckhouse/virtualization/api/client/kubeclient" "github.com/deckhouse/virtualization/api/core/v1alpha2" + "github.com/deckhouse/virtualization/api/core/v1alpha3" ) const ( @@ -222,6 +224,7 @@ func main() { clientgoscheme.AddToScheme, extv1.AddToScheme, v1alpha2.AddToScheme, + v1alpha3.AddToScheme, cdiv1beta1.AddToScheme, virtv1.AddToScheme, vsv1.AddToScheme, @@ -296,18 +299,23 @@ func main() { // Setup context to gracefully handle termination. ctx := signals.SetupSignalHandler() - onlyMigrationClient, err := client.New(cfg, client.Options{Scheme: scheme}) + preManagerClient, err := client.New(cfg, client.Options{Scheme: scheme}) if err != nil { log.Error(err.Error()) os.Exit(1) } - mCtrl, err := migration.NewController(onlyMigrationClient, log) + mCtrl, err := migration.NewController(preManagerClient, log) if err != nil { log.Error(err.Error()) os.Exit(1) } mCtrl.Run(ctx) + if err = crd.EnsureVMClassConversionWebhook(ctx, preManagerClient, controllerNamespace); err != nil { + log.Error("Failed to ensure VirtualMachineClass CRD conversion webhook", logger.SlogErr(err)) + os.Exit(1) + } + if err = indexer.IndexALL(ctx, mgr); err != nil { log.Error(err.Error()) os.Exit(1) diff --git a/images/virtualization-artifact/go.mod b/images/virtualization-artifact/go.mod index 7acf9e46f5..45fbb3f22a 100644 --- a/images/virtualization-artifact/go.mod +++ b/images/virtualization-artifact/go.mod @@ -83,7 +83,7 @@ require ( github.com/google/cel-go v0.23.2 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect + github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect diff --git a/images/virtualization-artifact/go.sum b/images/virtualization-artifact/go.sum index e1a15aaec0..f1157c9053 100644 --- a/images/virtualization-artifact/go.sum +++ b/images/virtualization-artifact/go.sum @@ -158,8 +158,9 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= diff --git a/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go b/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go index 60f515657c..fafb20b163 100644 --- a/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go +++ b/images/virtualization-artifact/pkg/apiserver/api/generated/openapi/zz_generated.openapi.go @@ -158,6 +158,19 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/deckhouse/virtualization/api/core/v1alpha2.VirtualMachineStats": schema_virtualization_api_core_v1alpha2_VirtualMachineStats(ref), "github.com/deckhouse/virtualization/api/core/v1alpha2.VirtualMachineStatus": schema_virtualization_api_core_v1alpha2_VirtualMachineStatus(ref), "github.com/deckhouse/virtualization/api/core/v1alpha2.WeightedVirtualMachineAndPodAffinityTerm": schema_virtualization_api_core_v1alpha2_WeightedVirtualMachineAndPodAffinityTerm(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.CPU": schema_virtualization_api_core_v1alpha3_CPU(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.CpuDiscovery": schema_virtualization_api_core_v1alpha3_CpuDiscovery(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.CpuFeatures": schema_virtualization_api_core_v1alpha3_CpuFeatures(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.MemoryMinMax": schema_virtualization_api_core_v1alpha3_MemoryMinMax(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.NodeSelector": schema_virtualization_api_core_v1alpha3_NodeSelector(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicy": schema_virtualization_api_core_v1alpha3_SizingPolicy(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicyCores": schema_virtualization_api_core_v1alpha3_SizingPolicyCores(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicyMemory": schema_virtualization_api_core_v1alpha3_SizingPolicyMemory(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicyMemoryPerCore": schema_virtualization_api_core_v1alpha3_SizingPolicyMemoryPerCore(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.VirtualMachineClass": schema_virtualization_api_core_v1alpha3_VirtualMachineClass(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.VirtualMachineClassList": schema_virtualization_api_core_v1alpha3_VirtualMachineClassList(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.VirtualMachineClassSpec": schema_virtualization_api_core_v1alpha3_VirtualMachineClassSpec(ref), + "github.com/deckhouse/virtualization/api/core/v1alpha3.VirtualMachineClassStatus": schema_virtualization_api_core_v1alpha3_VirtualMachineClassStatus(ref), "github.com/deckhouse/virtualization/api/subresources/v1alpha2.VirtualMachineAddVolume": schema_virtualization_api_subresources_v1alpha2_VirtualMachineAddVolume(ref), "github.com/deckhouse/virtualization/api/subresources/v1alpha2.VirtualMachineCancelEvacuation": schema_virtualization_api_subresources_v1alpha2_VirtualMachineCancelEvacuation(ref), "github.com/deckhouse/virtualization/api/subresources/v1alpha2.VirtualMachineConsole": schema_virtualization_api_subresources_v1alpha2_VirtualMachineConsole(ref), @@ -6060,6 +6073,580 @@ func schema_virtualization_api_core_v1alpha2_WeightedVirtualMachineAndPodAffinit } } +func schema_virtualization_api_core_v1alpha3_CPU(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "CPU defines the requirements for the virtual CPU model.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "type": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "model": { + SchemaProps: spec.SchemaProps{ + Description: "CPU model name. For more information about CPU models and topology, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology).", + Type: []string{"string"}, + Format: "", + }, + }, + "features": { + SchemaProps: spec.SchemaProps{ + Description: "List of CPU instructions (features) required when type=Features. For more information about CPU features, refer to the [libvirt docs](https://libvirt.org/formatdomain.html#cpu-model-and-topology).", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "discovery": { + SchemaProps: spec.SchemaProps{ + Description: "Create a CPU model based on intersecting CPU features for selected nodes.", + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.CpuDiscovery"), + }, + }, + }, + Required: []string{"type"}, + }, + }, + Dependencies: []string{ + "github.com/deckhouse/virtualization/api/core/v1alpha3.CpuDiscovery"}, + } +} + +func schema_virtualization_api_core_v1alpha3_CpuDiscovery(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "nodeSelector": { + SchemaProps: spec.SchemaProps{ + Description: "A selection of nodes to be used as the basis for creating a universal CPU model.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"}, + } +} + +func schema_virtualization_api_core_v1alpha3_CpuFeatures(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "CpuFeatures Information on CPU features supported by this model. Shown only for `Features` or `Discovery` types.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "enabled": { + SchemaProps: spec.SchemaProps{ + Description: "List of CPU features for this model.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "notEnabledCommon": { + SchemaProps: spec.SchemaProps{ + Description: "List of unused processor features additionally available for a given group of nodes.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func schema_virtualization_api_core_v1alpha3_MemoryMinMax(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "min": { + SchemaProps: spec.SchemaProps{ + Description: "Minimum amount of memory.", + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + "max": { + SchemaProps: spec.SchemaProps{ + Description: "Maximum amount of memory.", + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/api/resource.Quantity"}, + } +} + +func schema_virtualization_api_core_v1alpha3_NodeSelector(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "NodeSelector defines the nodes targeted for VM scheduling.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "matchLabels": { + SchemaProps: spec.SchemaProps{ + Description: "A map of {key,value} pairs. A single {key,value} pair in the matchLabels map is equivalent to an element of matchExpressions whose key field is \"key\", operator is \"In\", and the value array contains only \"value\". The requirements are ANDed.", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "matchExpressions": { + SchemaProps: spec.SchemaProps{ + Description: "A list of node selector requirements by node's labels.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/api/core/v1.NodeSelectorRequirement"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/api/core/v1.NodeSelectorRequirement"}, + } +} + +func schema_virtualization_api_core_v1alpha3_SizingPolicy(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "SizingPolicy defines a policy for allocating computational resources to VMs. It is represented as a list. The cores.min - cores.max ranges for different elements of the list must not overlap.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "memory": { + SchemaProps: spec.SchemaProps{ + Description: "Memory sizing policy.", + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicyMemory"), + }, + }, + "coreFractions": { + SchemaProps: spec.SchemaProps{ + Description: "Allowed values of the `coreFraction` parameter in percentages (e.g., \"5%\", \"10%\", \"25%\", \"50%\", \"100%\").", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "dedicatedCores": { + SchemaProps: spec.SchemaProps{ + Description: "Allowed values of the `dedicatedCores` parameter.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: false, + Type: []string{"boolean"}, + Format: "", + }, + }, + }, + }, + }, + "cores": { + SchemaProps: spec.SchemaProps{ + Description: "The policy applies for a specified range of the number of CPU cores.", + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicyCores"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicyCores", "github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicyMemory"}, + } +} + +func schema_virtualization_api_core_v1alpha3_SizingPolicyCores(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "min": { + SchemaProps: spec.SchemaProps{ + Description: "Minimum number of CPU cores.", + Default: 0, + Type: []string{"integer"}, + Format: "int32", + }, + }, + "max": { + SchemaProps: spec.SchemaProps{ + Description: "Maximum number of CPU cores.", + Default: 0, + Type: []string{"integer"}, + Format: "int32", + }, + }, + "step": { + SchemaProps: spec.SchemaProps{ + Description: "Discretization step for the CPU core number. For example, the combination of `min=2`, `max=10`, and `step=4` allows to set the number of virtual machine CPU cores to 2, 6, or 10.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + Required: []string{"min", "max"}, + }, + }, + } +} + +func schema_virtualization_api_core_v1alpha3_SizingPolicyMemory(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "min": { + SchemaProps: spec.SchemaProps{ + Description: "Minimum amount of memory.", + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + "max": { + SchemaProps: spec.SchemaProps{ + Description: "Maximum amount of memory.", + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + "step": { + SchemaProps: spec.SchemaProps{ + Description: "Memory size discretization step. For example, the combination of `min=2Gi, `max=4Gi` and `step=1Gi` allows to set the virtual machine memory size to 2Gi, 3Gi, or 4Gi.", + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + "perCore": { + SchemaProps: spec.SchemaProps{ + Description: "Amount of memory per CPU core.", + Default: map[string]interface{}{}, + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicyMemoryPerCore"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicyMemoryPerCore", "k8s.io/apimachinery/pkg/api/resource.Quantity"}, + } +} + +func schema_virtualization_api_core_v1alpha3_SizingPolicyMemoryPerCore(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "min": { + SchemaProps: spec.SchemaProps{ + Description: "Minimum amount of memory.", + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + "max": { + SchemaProps: spec.SchemaProps{ + Description: "Maximum amount of memory.", + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/api/resource.Quantity"}, + } +} + +func schema_virtualization_api_core_v1alpha3_VirtualMachineClass(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "VirtualMachineClass resource describes CPU requirements, node placement, and sizing policy for VM resources. A resource cannot be deleted as long as it is used in one of the VMs.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.VirtualMachineClassSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.VirtualMachineClassStatus"), + }, + }, + }, + Required: []string{"spec"}, + }, + }, + Dependencies: []string{ + "github.com/deckhouse/virtualization/api/core/v1alpha3.VirtualMachineClassSpec", "github.com/deckhouse/virtualization/api/core/v1alpha3.VirtualMachineClassStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_virtualization_api_core_v1alpha3_VirtualMachineClassList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "VirtualMachineClassList contains a list of VirtualMachineClasses.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "Items provides a list of VirtualMachineClasses.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.VirtualMachineClass"), + }, + }, + }, + }, + }, + }, + Required: []string{"metadata", "items"}, + }, + }, + Dependencies: []string{ + "github.com/deckhouse/virtualization/api/core/v1alpha3.VirtualMachineClass", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + +func schema_virtualization_api_core_v1alpha3_VirtualMachineClassSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "nodeSelector": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.NodeSelector"), + }, + }, + "tolerations": { + SchemaProps: spec.SchemaProps{ + Description: "Tolerations are the same as `spec.tolerations` for [pods](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/). These tolerations will be merged with the tolerations specified in the VirtualMachine resource. VirtualMachine tolerations have a higher priority.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/api/core/v1.Toleration"), + }, + }, + }, + }, + }, + "cpu": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.CPU"), + }, + }, + "sizingPolicies": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicy"), + }, + }, + }, + }, + }, + }, + Required: []string{"cpu"}, + }, + }, + Dependencies: []string{ + "github.com/deckhouse/virtualization/api/core/v1alpha3.CPU", "github.com/deckhouse/virtualization/api/core/v1alpha3.NodeSelector", "github.com/deckhouse/virtualization/api/core/v1alpha3.SizingPolicy", "k8s.io/api/core/v1.Toleration"}, + } +} + +func schema_virtualization_api_core_v1alpha3_VirtualMachineClassStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "phase": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "cpuFeatures": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/deckhouse/virtualization/api/core/v1alpha3.CpuFeatures"), + }, + }, + "availableNodes": { + SchemaProps: spec.SchemaProps{ + Description: "List of nodes that support this CPU model. It is not displayed for the following types: `Host`, `HostPassthrough`.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "maxAllocatableResources": { + SchemaProps: spec.SchemaProps{ + Description: "Maximum amount of free CPU and memory resources observed among all available nodes.", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + }, + }, + }, + "conditions": { + SchemaProps: spec.SchemaProps{ + Description: "The latest detailed observations of the VirtualMachineClass resource.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + }, + }, + }, + }, + }, + "observedGeneration": { + SchemaProps: spec.SchemaProps{ + Description: "Resource generation last processed by the controller.", + Type: []string{"integer"}, + Format: "int64", + }, + }, + }, + Required: []string{"phase"}, + }, + }, + Dependencies: []string{ + "github.com/deckhouse/virtualization/api/core/v1alpha3.CpuFeatures", "k8s.io/apimachinery/pkg/api/resource.Quantity", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, + } +} + func schema_virtualization_api_subresources_v1alpha2_VirtualMachineAddVolume(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go index a7c3eaa915..96033a289c 100644 --- a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go +++ b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_controller.go @@ -31,6 +31,7 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/eventrecord" "github.com/deckhouse/virtualization-controller/pkg/logger" "github.com/deckhouse/virtualization/api/core/v1alpha2" + "github.com/deckhouse/virtualization/api/core/v1alpha3" ) const ( @@ -67,9 +68,18 @@ func NewController( return nil, err } + validator := NewValidator(mgr.GetClient(), log, recorder, vmClassService) + if err = builder.WebhookManagedBy(mgr). For(&v1alpha2.VirtualMachineClass{}). - WithValidator(NewValidator(mgr.GetClient(), log, recorder, vmClassService)). + WithValidator(validator). + Complete(); err != nil { + return nil, err + } + + if err = builder.WebhookManagedBy(mgr). + For(&v1alpha3.VirtualMachineClass{}). + WithValidator(validator). Complete(); err != nil { return nil, err } diff --git a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go index 5f0fbe6a7e..eea4f0da7c 100644 --- a/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go +++ b/images/virtualization-artifact/pkg/controller/vmclass/vmclass_webhook.go @@ -26,6 +26,7 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/controller/vmclass/internal/validators" "github.com/deckhouse/virtualization-controller/pkg/eventrecord" "github.com/deckhouse/virtualization/api/core/v1alpha2" + "github.com/deckhouse/virtualization/api/core/v1alpha3" ) type VirtualMachineClassValidator interface { @@ -50,9 +51,18 @@ func NewValidator(client client.Client, log *log.Logger, recorder eventrecord.Ev } func (v *Validator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { - vmclass, ok := obj.(*v1alpha2.VirtualMachineClass) - if !ok { - return nil, fmt.Errorf("expected a new VirtualMachine but got a %T", obj) + var vmclass *v1alpha2.VirtualMachineClass + + switch obj := obj.(type) { + case *v1alpha2.VirtualMachineClass: + vmclass = obj + case *v1alpha3.VirtualMachineClass: + vmclass = &v1alpha2.VirtualMachineClass{} + if err := obj.ConvertTo(vmclass); err != nil { + return nil, fmt.Errorf("failed to convert v1alpha3 to v1alpha2: %w", err) + } + default: + return nil, fmt.Errorf("expected a VirtualMachineClass but got a %T", obj) } var warnings admission.Warnings @@ -69,13 +79,29 @@ func (v *Validator) ValidateCreate(ctx context.Context, obj runtime.Object) (adm } func (v *Validator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) { - oldVMClass, ok := oldObj.(*v1alpha2.VirtualMachineClass) - if !ok { + var oldVMClass, newVMClass *v1alpha2.VirtualMachineClass + + switch oldObj := oldObj.(type) { + case *v1alpha2.VirtualMachineClass: + oldVMClass = oldObj + case *v1alpha3.VirtualMachineClass: + oldVMClass = &v1alpha2.VirtualMachineClass{} + if err := oldObj.ConvertTo(oldVMClass); err != nil { + return nil, fmt.Errorf("failed to convert old v1alpha3 to v1alpha2: %w", err) + } + default: return nil, fmt.Errorf("expected an old VirtualMachineClass but got a %T", oldObj) } - newVMClass, ok := newObj.(*v1alpha2.VirtualMachineClass) - if !ok { + switch newObj := newObj.(type) { + case *v1alpha2.VirtualMachineClass: + newVMClass = newObj + case *v1alpha3.VirtualMachineClass: + newVMClass = &v1alpha2.VirtualMachineClass{} + if err := newObj.ConvertTo(newVMClass); err != nil { + return nil, fmt.Errorf("failed to convert new v1alpha3 to v1alpha2: %w", err) + } + default: return nil, fmt.Errorf("expected a new VirtualMachineClass but got a %T", newObj) } diff --git a/images/virtualization-artifact/pkg/crd/ensure_conversion.go b/images/virtualization-artifact/pkg/crd/ensure_conversion.go new file mode 100644 index 0000000000..cc8f1c90f7 --- /dev/null +++ b/images/virtualization-artifact/pkg/crd/ensure_conversion.go @@ -0,0 +1,74 @@ +/* +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 crd + +import ( + "context" + "fmt" + "os" + + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" +) + +const ( + vmClassCRDName = "virtualmachineclasses.virtualization.deckhouse.io" + tlsCertPath = "/tmp/k8s-webhook-server/serving-certs/ca.crt" +) + +// EnsureVMClassConversionWebhook configures the VirtualMachineClass CRD to use webhook-based conversion. +// This allows Kubernetes to convert between v1alpha2 (storage version) and v1alpha3 (served version). +// Returns nil if conversion is already configured, otherwise returns an error. +func EnsureVMClassConversionWebhook(ctx context.Context, c client.Client, controllerNamespace string) error { + logger := log.FromContext(ctx).WithName("crd-conversion") + + crd := &apiextensionsv1.CustomResourceDefinition{} + if err := c.Get(ctx, client.ObjectKey{Name: vmClassCRDName}, crd); err != nil { + return fmt.Errorf("get VirtualMachineClass CRD: %w", err) + } + + caBundle, err := os.ReadFile(tlsCertPath) + if err != nil { + return fmt.Errorf("read TLS CA certificate from %s: %w", tlsCertPath, err) + } + + crd.Spec.Conversion = &apiextensionsv1.CustomResourceConversion{ + Strategy: apiextensionsv1.WebhookConverter, + Webhook: &apiextensionsv1.WebhookConversion{ + ClientConfig: &apiextensionsv1.WebhookClientConfig{ + Service: &apiextensionsv1.ServiceReference{ + Name: "virtualization-controller", + Namespace: controllerNamespace, + Path: ptr.To("/convert"), + Port: ptr.To[int32](443), + }, + CABundle: caBundle, + }, + ConversionReviewVersions: []string{"v1"}, + }, + } + + if err := c.Update(ctx, crd); err != nil { + logger.Error(err, "Failed to update VirtualMachineClass CRD with conversion webhook configuration") + return fmt.Errorf("update CRD with conversion webhook: %w", err) + } + + logger.Info("Successfully configured VirtualMachineClass CRD with webhook conversion") + return nil +} diff --git a/src/cli/go.mod b/src/cli/go.mod index 4d728824a2..bd767e6226 100644 --- a/src/cli/go.mod +++ b/src/cli/go.mod @@ -69,6 +69,7 @@ require ( kubevirt.io/api v1.3.1 // indirect kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 // indirect kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 // indirect + sigs.k8s.io/controller-runtime v0.21.0 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect diff --git a/src/cli/go.sum b/src/cli/go.sum index a6acb020c5..7c203f2035 100644 --- a/src/cli/go.sum +++ b/src/cli/go.sum @@ -191,8 +191,8 @@ github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xl github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= -github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= +github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= @@ -214,8 +214,8 @@ github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3ev github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= -github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= -github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw= +github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= github.com/openshift/api v0.0.0-20230503133300-8bbcb7ca7183 h1:t/CahSnpqY46sQR01SoS+Jt0jtjgmhgE6lFmRnO4q70= github.com/openshift/api v0.0.0-20230503133300-8bbcb7ca7183/go.mod h1:4VWG+W22wrB4HfBL88P40DxLEpSOaiBVxUnfalfJo9k= github.com/openshift/custom-resource-status v1.1.2 h1:C3DL44LEbvlbItfd8mT5jWrqPfHnSOQoQf/sypqA6A4= @@ -593,6 +593,8 @@ kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 h1:IWo12+ei3jltSN5jQN kubevirt.io/containerized-data-importer-api v1.57.0-alpha1/go.mod h1:Y/8ETgHS1GjO89bl682DPtQOYEU/1ctPFBz6Sjxm4DM= kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 h1:QMrd0nKP0BGbnxTqakhDZAUhGKxPiPiN5gSDqKUmGGc= kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90/go.mod h1:018lASpFYBsYN6XwmA2TIrPCx6e0gviTd/ZNtSitKgc= +sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8= +sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= @@ -603,7 +605,6 @@ sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxO sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= -sigs.k8s.io/structured-merge-diff/v6 v6.2.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= diff --git a/templates/virtualization-controller/rbac-for-us.yaml b/templates/virtualization-controller/rbac-for-us.yaml index c80363ec94..5355971813 100644 --- a/templates/virtualization-controller/rbac-for-us.yaml +++ b/templates/virtualization-controller/rbac-for-us.yaml @@ -249,6 +249,14 @@ rules: - get - list - watch +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - update + - patch --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding diff --git a/templates/virtualization-controller/validation-webhook.yaml b/templates/virtualization-controller/validation-webhook.yaml index 87d3655cb5..9d29166f4f 100644 --- a/templates/virtualization-controller/validation-webhook.yaml +++ b/templates/virtualization-controller/validation-webhook.yaml @@ -209,7 +209,7 @@ webhooks: {{ .Values.virtualization.internal.controller.cert.ca | b64enc }} admissionReviewVersions: ["v1"] sideEffects: None - - name: "vmclass.virtualization-controller.validate.d8-virtualization" + - name: "vmclass-v1alpha2.virtualization-controller.validate.d8-virtualization" rules: - apiGroups: ["virtualization.deckhouse.io"] apiVersions: ["v1alpha2"] @@ -226,6 +226,23 @@ webhooks: {{ .Values.virtualization.internal.controller.cert.ca | b64enc }} admissionReviewVersions: ["v1"] sideEffects: None + - name: "vmclass-v1alpha3.virtualization-controller.validate.d8-virtualization" + rules: + - apiGroups: ["virtualization.deckhouse.io"] + apiVersions: ["v1alpha3"] + operations: ["CREATE", "UPDATE"] + resources: ["virtualmachineclasses"] + scope: "Cluster" + clientConfig: + service: + namespace: d8-{{ .Chart.Name }} + name: virtualization-controller + path: /validate-virtualization-deckhouse-io-v1alpha3-virtualmachineclass + port: 443 + caBundle: | + {{ .Values.virtualization.internal.controller.cert.ca | b64enc }} + admissionReviewVersions: ["v1"] + sideEffects: None - name: "moduleconfig.virtualization-controller.validate.d8-virtualization" rules: - apiGroups: ["deckhouse.io"] diff --git a/templates/virtualization-controller/vmclasses-default.yaml b/templates/virtualization-controller/vmclasses-default.yaml index f2beb27764..2bbf9c7288 100644 --- a/templates/virtualization-controller/vmclasses-default.yaml +++ b/templates/virtualization-controller/vmclasses-default.yaml @@ -1,4 +1,4 @@ -apiVersion: virtualization.deckhouse.io/v1alpha2 +apiVersion: virtualization.deckhouse.io/v1alpha3 kind: VirtualMachineClass metadata: name: generic @@ -16,19 +16,19 @@ spec: min: 1 max: 4 dedicatedCores: [false] - coreFractions: [5, 10, 20, 50, 100] + coreFractions: ["5%", "10%", "20%", "50%", "100%"] - cores: min: 5 max: 8 dedicatedCores: [false] - coreFractions: [20, 50, 100] + coreFractions: ["20%", "50%", "100%"] - cores: min: 9 max: 16 dedicatedCores: [true, false] - coreFractions: [50, 100] + coreFractions: ["50%", "100%"] - cores: min: 17 max: 1024 dedicatedCores: [true, false] - coreFractions: [100] + coreFractions: ["100%"] diff --git a/test/e2e/go.mod b/test/e2e/go.mod index 34da7ca6ef..03f982b199 100644 --- a/test/e2e/go.mod +++ b/test/e2e/go.mod @@ -9,7 +9,6 @@ require ( github.com/deckhouse/virtualization/api v0.0.0-20240923080356-bb5809dba578 github.com/onsi/ginkgo/v2 v2.22.0 github.com/onsi/gomega v1.36.1 - golang.org/x/sync v0.14.0 gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.33.3 k8s.io/apimachinery v0.33.3 @@ -38,7 +37,7 @@ require ( github.com/google/btree v1.1.3 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect + github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect @@ -64,6 +63,7 @@ require ( go.yaml.in/yaml/v3 v3.0.3 // indirect golang.org/x/net v0.39.0 // indirect golang.org/x/oauth2 v0.27.0 // indirect + golang.org/x/sync v0.14.0 // indirect golang.org/x/sys v0.33.0 // indirect golang.org/x/term v0.32.0 // indirect golang.org/x/text v0.25.0 // indirect diff --git a/test/e2e/go.sum b/test/e2e/go.sum index f59519457d..bcef76dedb 100644 --- a/test/e2e/go.sum +++ b/test/e2e/go.sum @@ -111,8 +111,8 @@ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= diff --git a/test/e2e/legacy/sizing_policy.go b/test/e2e/legacy/sizing_policy.go index a2d644908e..90539c832a 100644 --- a/test/e2e/legacy/sizing_policy.go +++ b/test/e2e/legacy/sizing_policy.go @@ -19,7 +19,6 @@ package legacy import ( "fmt" "slices" - "strconv" "strings" . "github.com/onsi/ginkgo/v2" @@ -28,6 +27,7 @@ import ( "github.com/deckhouse/virtualization/api/core/v1alpha2" "github.com/deckhouse/virtualization/api/core/v1alpha2/vmcondition" + "github.com/deckhouse/virtualization/api/core/v1alpha3" kc "github.com/deckhouse/virtualization/test/e2e/internal/kubectl" "github.com/deckhouse/virtualization/test/e2e/internal/util" ) @@ -177,7 +177,7 @@ var _ = Describe("SizingPolicy", Ordered, func() { }) It("creates new `VirtualMachineClass`", func() { - vmClass := v1alpha2.VirtualMachineClass{} + vmClass := v1alpha3.VirtualMachineClass{} err := GetObject(kc.ResourceVMClass, vmClassDiscovery, &vmClass, kc.GetOptions{}) Expect(err).NotTo(HaveOccurred()) vmClass.Name = vmClassDiscoveryCopy @@ -214,7 +214,7 @@ var _ = Describe("SizingPolicy", Ordered, func() { Expect(res.Error()).NotTo(HaveOccurred(), res.StdErr()) vms := strings.Split(res.StdOut(), " ") - vmClass := v1alpha2.VirtualMachineClass{} + vmClass := v1alpha3.VirtualMachineClass{} err := GetObject(kc.ResourceVMClass, vmClassDiscovery, &vmClass, kc.GetOptions{}) Expect(err).NotTo(HaveOccurred()) @@ -238,8 +238,8 @@ var _ = Describe("SizingPolicy", Ordered, func() { }) }) -func ValidateVirtualMachineByClass(virtualMachineClass *v1alpha2.VirtualMachineClass, virtualMachine *v1alpha2.VirtualMachine) { - var sizingPolicy v1alpha2.SizingPolicy +func ValidateVirtualMachineByClass(virtualMachineClass *v1alpha3.VirtualMachineClass, virtualMachine *v1alpha2.VirtualMachine) { + var sizingPolicy v1alpha3.SizingPolicy for _, p := range virtualMachineClass.Spec.SizingPolicies { if virtualMachine.Spec.CPU.Cores >= p.Cores.Min && virtualMachine.Spec.CPU.Cores <= p.Cores.Max { sizingPolicy = *p.DeepCopy() @@ -252,9 +252,7 @@ func ValidateVirtualMachineByClass(virtualMachineClass *v1alpha2.VirtualMachineC checkMemory := checkMinMemory && checkMaxMemory Expect(checkMemory).To(BeTrue(), fmt.Errorf("memory size outside of possible interval '%v - %v': %v", sizingPolicy.Memory.Min, sizingPolicy.Memory.Max, virtualMachine.Spec.Memory.Size)) - coreFraction, err := strconv.Atoi(strings.ReplaceAll(virtualMachine.Spec.CPU.CoreFraction, "%", "")) - Expect(err).NotTo(HaveOccurred(), "cannot convert CoreFraction value to integer: %s", err) - checkCoreFraction := slices.Contains(sizingPolicy.CoreFractions, v1alpha2.CoreFractionValue(coreFraction)) + checkCoreFraction := slices.Contains(sizingPolicy.CoreFractions, v1alpha3.CoreFractionValue(virtualMachine.Spec.CPU.CoreFraction)) Expect(checkCoreFraction).To(BeTrue(), fmt.Errorf("sizing policy core fraction list does not contain value from spec: %s\n%v", virtualMachine.Spec.CPU.CoreFraction, sizingPolicy.CoreFractions)) } diff --git a/test/e2e/legacy/testdata/affinity-toleration/transformer.yaml b/test/e2e/legacy/testdata/affinity-toleration/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/affinity-toleration/transformer.yaml +++ b/test/e2e/legacy/testdata/affinity-toleration/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/affinity-toleration/vm/base/transformer.yaml b/test/e2e/legacy/testdata/affinity-toleration/vm/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/affinity-toleration/vm/base/transformer.yaml +++ b/test/e2e/legacy/testdata/affinity-toleration/vm/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/affinity-toleration/vmc.yaml b/test/e2e/legacy/testdata/affinity-toleration/vmc.yaml index d5a4a38b29..68c1540fca 100644 --- a/test/e2e/legacy/testdata/affinity-toleration/vmc.yaml +++ b/test/e2e/legacy/testdata/affinity-toleration/vmc.yaml @@ -1,4 +1,4 @@ -apiVersion: virtualization.deckhouse.io/v1alpha2 +apiVersion: virtualization.deckhouse.io/v1alpha3 kind: VirtualMachineClass metadata: name: affinity-toleration-discovery diff --git a/test/e2e/legacy/testdata/complex-test/transformer.yaml b/test/e2e/legacy/testdata/complex-test/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/complex-test/transformer.yaml +++ b/test/e2e/legacy/testdata/complex-test/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/complex-test/vm/base/transformer.yaml b/test/e2e/legacy/testdata/complex-test/vm/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/complex-test/vm/base/transformer.yaml +++ b/test/e2e/legacy/testdata/complex-test/vm/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/complex-test/vmc.yaml b/test/e2e/legacy/testdata/complex-test/vmc.yaml index 7ef9aaf78b..672336653a 100644 --- a/test/e2e/legacy/testdata/complex-test/vmc.yaml +++ b/test/e2e/legacy/testdata/complex-test/vmc.yaml @@ -1,4 +1,4 @@ -apiVersion: virtualization.deckhouse.io/v1alpha2 +apiVersion: virtualization.deckhouse.io/v1alpha3 kind: VirtualMachineClass metadata: name: complex-discovery diff --git a/test/e2e/legacy/testdata/connectivity/transformer.yaml b/test/e2e/legacy/testdata/connectivity/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/connectivity/transformer.yaml +++ b/test/e2e/legacy/testdata/connectivity/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/disk-resizing/base/transformer.yaml b/test/e2e/legacy/testdata/disk-resizing/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/disk-resizing/base/transformer.yaml +++ b/test/e2e/legacy/testdata/disk-resizing/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/disk-resizing/transformer.yaml b/test/e2e/legacy/testdata/disk-resizing/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/disk-resizing/transformer.yaml +++ b/test/e2e/legacy/testdata/disk-resizing/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/image-hotplug/base/transformer.yaml b/test/e2e/legacy/testdata/image-hotplug/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/image-hotplug/base/transformer.yaml +++ b/test/e2e/legacy/testdata/image-hotplug/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/image-hotplug/transformer.yaml b/test/e2e/legacy/testdata/image-hotplug/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/image-hotplug/transformer.yaml +++ b/test/e2e/legacy/testdata/image-hotplug/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/sizing-policy/base/transformer.yaml b/test/e2e/legacy/testdata/sizing-policy/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/sizing-policy/base/transformer.yaml +++ b/test/e2e/legacy/testdata/sizing-policy/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/sizing-policy/transformer.yaml b/test/e2e/legacy/testdata/sizing-policy/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/sizing-policy/transformer.yaml +++ b/test/e2e/legacy/testdata/sizing-policy/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/sizing-policy/vmc.yaml b/test/e2e/legacy/testdata/sizing-policy/vmc.yaml index 48baa39771..50c098e2f8 100644 --- a/test/e2e/legacy/testdata/sizing-policy/vmc.yaml +++ b/test/e2e/legacy/testdata/sizing-policy/vmc.yaml @@ -1,4 +1,4 @@ -apiVersion: virtualization.deckhouse.io/v1alpha2 +apiVersion: virtualization.deckhouse.io/v1alpha3 kind: VirtualMachineClass metadata: name: sizing-policy-discovery @@ -18,11 +18,11 @@ spec: - worker sizingPolicies: - coreFractions: - - 5 - - 10 - - 20 - - 50 - - 100 + - "5%" + - "10%" + - "20%" + - "50%" + - "100%" cores: max: 4 min: 1 @@ -33,9 +33,9 @@ spec: min: 1Gi step: 512Mi - coreFractions: - - 20 - - 50 - - 100 + - "20%" + - "50%" + - "100%" cores: max: 8 min: 5 @@ -46,8 +46,8 @@ spec: min: 5Gi step: 1Gi - coreFractions: - - 50 - - 100 + - "50%" + - "100%" cores: max: 16 min: 9 @@ -59,7 +59,7 @@ spec: min: 9Gi step: 1Gi - coreFractions: - - 100 + - "100%" cores: max: 1024 min: 17 diff --git a/test/e2e/legacy/testdata/templates/transformer.yaml b/test/e2e/legacy/testdata/templates/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/templates/transformer.yaml +++ b/test/e2e/legacy/testdata/templates/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vd-snapshots/transformer.yaml b/test/e2e/legacy/testdata/vd-snapshots/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vd-snapshots/transformer.yaml +++ b/test/e2e/legacy/testdata/vd-snapshots/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vd-snapshots/vm/base/transformer.yaml b/test/e2e/legacy/testdata/vd-snapshots/vm/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/vd-snapshots/vm/base/transformer.yaml +++ b/test/e2e/legacy/testdata/vd-snapshots/vm/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-configuration/base/transformer.yaml b/test/e2e/legacy/testdata/vm-configuration/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/vm-configuration/base/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-configuration/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-configuration/transformer.yaml b/test/e2e/legacy/testdata/vm-configuration/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vm-configuration/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-configuration/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-disk-attachment/base/transformer.yaml b/test/e2e/legacy/testdata/vm-disk-attachment/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/vm-disk-attachment/base/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-disk-attachment/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-disk-attachment/transformer.yaml b/test/e2e/legacy/testdata/vm-disk-attachment/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vm-disk-attachment/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-disk-attachment/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-evacuation/transformer.yaml b/test/e2e/legacy/testdata/vm-evacuation/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vm-evacuation/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-evacuation/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-evacuation/vm/base/transformer.yaml b/test/e2e/legacy/testdata/vm-evacuation/vm/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/vm-evacuation/vm/base/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-evacuation/vm/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-label-annotation/base/transformer.yaml b/test/e2e/legacy/testdata/vm-label-annotation/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/vm-label-annotation/base/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-label-annotation/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-label-annotation/transformer.yaml b/test/e2e/legacy/testdata/vm-label-annotation/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vm-label-annotation/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-label-annotation/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-migration-cancel/transformer.yaml b/test/e2e/legacy/testdata/vm-migration-cancel/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vm-migration-cancel/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-migration-cancel/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-migration-cancel/vm/base/transformer.yaml b/test/e2e/legacy/testdata/vm-migration-cancel/vm/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/vm-migration-cancel/vm/base/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-migration-cancel/vm/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-migration/transformer.yaml b/test/e2e/legacy/testdata/vm-migration/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vm-migration/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-migration/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-migration/vm/base/transformer.yaml b/test/e2e/legacy/testdata/vm-migration/vm/base/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/vm-migration/vm/base/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-migration/vm/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-restore-force/transformer.yaml b/test/e2e/legacy/testdata/vm-restore-force/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vm-restore-force/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-restore-force/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-restore-force/vm/base/transformer.yaml b/test/e2e/legacy/testdata/vm-restore-force/vm/base/transformer.yaml index 2a24df6226..2659eb381a 100644 --- a/test/e2e/legacy/testdata/vm-restore-force/vm/base/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-restore-force/vm/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-restore-safe/transformer.yaml b/test/e2e/legacy/testdata/vm-restore-safe/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vm-restore-safe/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-restore-safe/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-restore-safe/vm/base/transformer.yaml b/test/e2e/legacy/testdata/vm-restore-safe/vm/base/transformer.yaml index 2a24df6226..2659eb381a 100644 --- a/test/e2e/legacy/testdata/vm-restore-safe/vm/base/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-restore-safe/vm/base/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-versions/transformer.yaml b/test/e2e/legacy/testdata/vm-versions/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vm-versions/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-versions/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-versions/vm/transformer.yaml b/test/e2e/legacy/testdata/vm-versions/vm/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/vm-versions/vm/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-versions/vm/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-vpc/transformer.yaml b/test/e2e/legacy/testdata/vm-vpc/transformer.yaml index e827a19238..ec70d37fcd 100644 --- a/test/e2e/legacy/testdata/vm-vpc/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-vpc/transformer.yaml @@ -46,7 +46,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-vpc/vm-bar/transformer.yaml b/test/e2e/legacy/testdata/vm-vpc/vm-bar/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/vm-vpc/vm-bar/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-vpc/vm-bar/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine diff --git a/test/e2e/legacy/testdata/vm-vpc/vm-foo/transformer.yaml b/test/e2e/legacy/testdata/vm-vpc/vm-foo/transformer.yaml index c70c289afa..1dc146a3af 100644 --- a/test/e2e/legacy/testdata/vm-vpc/vm-foo/transformer.yaml +++ b/test/e2e/legacy/testdata/vm-vpc/vm-foo/transformer.yaml @@ -48,7 +48,7 @@ nameReference: - path: spec/virtualMachineName kind: VirtualMachineBlockDeviceAttachment - kind: VirtualMachineClass - version: v1alpha2 + version: v1alpha3 fieldSpecs: - path: spec/virtualMachineClassName kind: VirtualMachine