From d99e352a388653b58ecd146388455d7c7adadb56 Mon Sep 17 00:00:00 2001
From: Philipp Matthes
Date: Mon, 29 Dec 2025 11:49:31 +0100
Subject: [PATCH 1/3] Extend hypervisor crd for cortex filtering
---
api/v1/hypervisor_types.go | 49 +++++++++++--
api/v1/zz_generated.deepcopy.go | 59 +++++++++++++--
...{capabilitiesstatus.go => capabilities.go} | 16 ++---
.../api/v1/domaincapabilities.go | 65 +++++++++++++++++
applyconfigurations/api/v1/hypervisorspec.go | 11 +++
.../api/v1/hypervisorstatus.go | 70 ++++++++++++++----
applyconfigurations/utils.go | 6 +-
.../crds/hypervisor-crd.yaml | 71 ++++++++++++++++++-
.../crd/bases/kvm.cloud.sap_hypervisors.yaml | 71 ++++++++++++++++++-
9 files changed, 382 insertions(+), 36 deletions(-)
rename applyconfigurations/api/v1/{capabilitiesstatus.go => capabilities.go} (62%)
create mode 100644 applyconfigurations/api/v1/domaincapabilities.go
diff --git a/api/v1/hypervisor_types.go b/api/v1/hypervisor_types.go
index e38a2e3..b6bf608 100644
--- a/api/v1/hypervisor_types.go
+++ b/api/v1/hypervisor_types.go
@@ -93,6 +93,12 @@ type HypervisorSpec struct {
// Aggregates are used to apply aggregates to the hypervisor.
Aggregates []string `json:"aggregates"`
+ // +kubebuilder:default:={}
+ // AllowedProjects defines which openstack projects are allowed to schedule
+ // instances on this hypervisor. The values of this list should be project
+ // uuids. If left empty, all projects are allowed.
+ AllowedProjects []string `json:"allowedProjects"`
+
// +kubebuilder:default:=true
// HighAvailability is used to enable the high availability handling of the hypervisor.
HighAvailability bool `json:"highAvailability"`
@@ -190,8 +196,8 @@ type OperatingSystemStatus struct {
GardenLinuxFeatures []string `json:"gardenLinuxFeatures,omitempty"`
}
-// Current capabilities reported by libvirt.
-type CapabilitiesStatus struct {
+// Capabilities of the hypervisor as reported by libvirt.
+type Capabilities struct {
// +kubebuilder:default:=unknown
// The hosts CPU architecture (not the guests).
HostCpuArch string `json:"cpuArch,omitempty"`
@@ -201,6 +207,26 @@ type CapabilitiesStatus struct {
HostCpus resource.Quantity `json:"cpus,omitempty"`
}
+// Domain capabilities of the hypervisor as reported by libvirt.
+// These details are relevant to check if a VM can be scheduled on the hypervisor.
+type DomainCapabilities struct {
+ // +kubebuilder:default:=unknown
+ // The available domain cpu architecture.
+ Arch string `json:"arch,omitempty"`
+ // +kubebuilder:default:=unknown
+ // The supported type of virtualization for domains, such as "ch".
+ HypervisorType string `json:"hypervisorType,omitempty"`
+ // +kubebuilder:default:={}
+ // Supported devices for domains, such as "video".
+ SupportedDevices []string `json:"supportedDevices,omitempty"`
+ // +kubebuilder:default:={}
+ // Supported cpu modes for domains, such as "host-passthrough".
+ SupportedCpuModes []string `json:"supportedCpuModes,omitempty"`
+ // +kubebuilder:default:={}
+ // Supported features for domains, such as "sev" or "sgx".
+ SupportedFeatures []string `json:"supportedFeatures,omitempty"`
+}
+
// HypervisorStatus defines the observed state of Hypervisor
type HypervisorStatus struct {
// +kubebuilder:default:=unknown
@@ -216,8 +242,23 @@ type HypervisorStatus struct {
// Represents the Hypervisor hosted Virtual Machines
Instances []Instance `json:"instances,omitempty"`
- // The capabilities of the hypervisors as reported by libvirt.
- Capabilities CapabilitiesStatus `json:"capabilities,omitempty"`
+ // Auto-discovered capabilities as reported by libvirt.
+ Capabilities Capabilities `json:"capabilities"`
+
+ // Auto-discovered domain capabilities relevant to check if a VM
+ // can be scheduled on the hypervisor.
+ DomainCapabilities DomainCapabilities `json:"domainCapabilities"`
+
+ // +kubebuilder:default:={}
+ // Auto-discovered capacity available in total on the hypervisor.
+ // The remaining physical capacity can be calculated
+ // as Capacity - Allocation.
+ Capacity map[string]resource.Quantity `json:"capacity,omitempty"`
+
+ // +kubebuilder:default:={}
+ // Auto-discovered capacity currently allocated by instances
+ // on the hypervisor. Note that this does not include reserved capacity.
+ Allocation map[string]resource.Quantity `json:"allocation,omitempty"`
// +kubebuilder:default:=0
// Represent the num of instances
diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go
index 1950f3b..7336a32 100644
--- a/api/v1/zz_generated.deepcopy.go
+++ b/api/v1/zz_generated.deepcopy.go
@@ -22,23 +22,54 @@ limitations under the License.
package v1
import (
+ "k8s.io/apimachinery/pkg/api/resource"
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 *CapabilitiesStatus) DeepCopyInto(out *CapabilitiesStatus) {
+func (in *Capabilities) DeepCopyInto(out *Capabilities) {
*out = *in
out.HostMemory = in.HostMemory.DeepCopy()
out.HostCpus = in.HostCpus.DeepCopy()
}
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CapabilitiesStatus.
-func (in *CapabilitiesStatus) DeepCopy() *CapabilitiesStatus {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Capabilities.
+func (in *Capabilities) DeepCopy() *Capabilities {
if in == nil {
return nil
}
- out := new(CapabilitiesStatus)
+ out := new(Capabilities)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *DomainCapabilities) DeepCopyInto(out *DomainCapabilities) {
+ *out = *in
+ if in.SupportedDevices != nil {
+ in, out := &in.SupportedDevices, &out.SupportedDevices
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
+ if in.SupportedCpuModes != nil {
+ in, out := &in.SupportedCpuModes, &out.SupportedCpuModes
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
+ if in.SupportedFeatures != nil {
+ in, out := &in.SupportedFeatures, &out.SupportedFeatures
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DomainCapabilities.
+func (in *DomainCapabilities) DeepCopy() *DomainCapabilities {
+ if in == nil {
+ return nil
+ }
+ out := new(DomainCapabilities)
in.DeepCopyInto(out)
return out
}
@@ -231,6 +262,11 @@ func (in *HypervisorSpec) DeepCopyInto(out *HypervisorSpec) {
*out = make([]string, len(*in))
copy(*out, *in)
}
+ if in.AllowedProjects != nil {
+ in, out := &in.AllowedProjects, &out.AllowedProjects
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HypervisorSpec.
@@ -254,6 +290,21 @@ func (in *HypervisorStatus) DeepCopyInto(out *HypervisorStatus) {
copy(*out, *in)
}
in.Capabilities.DeepCopyInto(&out.Capabilities)
+ in.DomainCapabilities.DeepCopyInto(&out.DomainCapabilities)
+ if in.Capacity != nil {
+ in, out := &in.Capacity, &out.Capacity
+ *out = make(map[string]resource.Quantity, len(*in))
+ for key, val := range *in {
+ (*out)[key] = val.DeepCopy()
+ }
+ }
+ if in.Allocation != nil {
+ in, out := &in.Allocation, &out.Allocation
+ *out = make(map[string]resource.Quantity, len(*in))
+ for key, val := range *in {
+ (*out)[key] = val.DeepCopy()
+ }
+ }
if in.Traits != nil {
in, out := &in.Traits, &out.Traits
*out = make([]string, len(*in))
diff --git a/applyconfigurations/api/v1/capabilitiesstatus.go b/applyconfigurations/api/v1/capabilities.go
similarity index 62%
rename from applyconfigurations/api/v1/capabilitiesstatus.go
rename to applyconfigurations/api/v1/capabilities.go
index 0ab1ec7..7b87dd8 100644
--- a/applyconfigurations/api/v1/capabilitiesstatus.go
+++ b/applyconfigurations/api/v1/capabilities.go
@@ -6,24 +6,24 @@ import (
resource "k8s.io/apimachinery/pkg/api/resource"
)
-// CapabilitiesStatusApplyConfiguration represents a declarative configuration of the CapabilitiesStatus type for use
+// CapabilitiesApplyConfiguration represents a declarative configuration of the Capabilities type for use
// with apply.
-type CapabilitiesStatusApplyConfiguration struct {
+type CapabilitiesApplyConfiguration struct {
HostCpuArch *string `json:"cpuArch,omitempty"`
HostMemory *resource.Quantity `json:"memory,omitempty"`
HostCpus *resource.Quantity `json:"cpus,omitempty"`
}
-// CapabilitiesStatusApplyConfiguration constructs a declarative configuration of the CapabilitiesStatus type for use with
+// CapabilitiesApplyConfiguration constructs a declarative configuration of the Capabilities type for use with
// apply.
-func CapabilitiesStatus() *CapabilitiesStatusApplyConfiguration {
- return &CapabilitiesStatusApplyConfiguration{}
+func Capabilities() *CapabilitiesApplyConfiguration {
+ return &CapabilitiesApplyConfiguration{}
}
// WithHostCpuArch sets the HostCpuArch field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the HostCpuArch field is set to the value of the last call.
-func (b *CapabilitiesStatusApplyConfiguration) WithHostCpuArch(value string) *CapabilitiesStatusApplyConfiguration {
+func (b *CapabilitiesApplyConfiguration) WithHostCpuArch(value string) *CapabilitiesApplyConfiguration {
b.HostCpuArch = &value
return b
}
@@ -31,7 +31,7 @@ func (b *CapabilitiesStatusApplyConfiguration) WithHostCpuArch(value string) *Ca
// WithHostMemory sets the HostMemory field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the HostMemory field is set to the value of the last call.
-func (b *CapabilitiesStatusApplyConfiguration) WithHostMemory(value resource.Quantity) *CapabilitiesStatusApplyConfiguration {
+func (b *CapabilitiesApplyConfiguration) WithHostMemory(value resource.Quantity) *CapabilitiesApplyConfiguration {
b.HostMemory = &value
return b
}
@@ -39,7 +39,7 @@ func (b *CapabilitiesStatusApplyConfiguration) WithHostMemory(value resource.Qua
// WithHostCpus sets the HostCpus field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the HostCpus field is set to the value of the last call.
-func (b *CapabilitiesStatusApplyConfiguration) WithHostCpus(value resource.Quantity) *CapabilitiesStatusApplyConfiguration {
+func (b *CapabilitiesApplyConfiguration) WithHostCpus(value resource.Quantity) *CapabilitiesApplyConfiguration {
b.HostCpus = &value
return b
}
diff --git a/applyconfigurations/api/v1/domaincapabilities.go b/applyconfigurations/api/v1/domaincapabilities.go
new file mode 100644
index 0000000..8985c23
--- /dev/null
+++ b/applyconfigurations/api/v1/domaincapabilities.go
@@ -0,0 +1,65 @@
+// Code generated by controller-gen. DO NOT EDIT.
+
+package v1
+
+// DomainCapabilitiesApplyConfiguration represents a declarative configuration of the DomainCapabilities type for use
+// with apply.
+type DomainCapabilitiesApplyConfiguration struct {
+ Arch *string `json:"arch,omitempty"`
+ HypervisorType *string `json:"hypervisorType,omitempty"`
+ SupportedDevices []string `json:"supportedDevices,omitempty"`
+ SupportedCpuModes []string `json:"supportedCpuModes,omitempty"`
+ SupportedFeatures []string `json:"supportedFeatures,omitempty"`
+}
+
+// DomainCapabilitiesApplyConfiguration constructs a declarative configuration of the DomainCapabilities type for use with
+// apply.
+func DomainCapabilities() *DomainCapabilitiesApplyConfiguration {
+ return &DomainCapabilitiesApplyConfiguration{}
+}
+
+// WithArch sets the Arch field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the Arch field is set to the value of the last call.
+func (b *DomainCapabilitiesApplyConfiguration) WithArch(value string) *DomainCapabilitiesApplyConfiguration {
+ b.Arch = &value
+ return b
+}
+
+// WithHypervisorType sets the HypervisorType field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the HypervisorType field is set to the value of the last call.
+func (b *DomainCapabilitiesApplyConfiguration) WithHypervisorType(value string) *DomainCapabilitiesApplyConfiguration {
+ b.HypervisorType = &value
+ return b
+}
+
+// WithSupportedDevices adds the given value to the SupportedDevices field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, values provided by each call will be appended to the SupportedDevices field.
+func (b *DomainCapabilitiesApplyConfiguration) WithSupportedDevices(values ...string) *DomainCapabilitiesApplyConfiguration {
+ for i := range values {
+ b.SupportedDevices = append(b.SupportedDevices, values[i])
+ }
+ return b
+}
+
+// WithSupportedCpuModes adds the given value to the SupportedCpuModes field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, values provided by each call will be appended to the SupportedCpuModes field.
+func (b *DomainCapabilitiesApplyConfiguration) WithSupportedCpuModes(values ...string) *DomainCapabilitiesApplyConfiguration {
+ for i := range values {
+ b.SupportedCpuModes = append(b.SupportedCpuModes, values[i])
+ }
+ return b
+}
+
+// WithSupportedFeatures adds the given value to the SupportedFeatures field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, values provided by each call will be appended to the SupportedFeatures field.
+func (b *DomainCapabilitiesApplyConfiguration) WithSupportedFeatures(values ...string) *DomainCapabilitiesApplyConfiguration {
+ for i := range values {
+ b.SupportedFeatures = append(b.SupportedFeatures, values[i])
+ }
+ return b
+}
diff --git a/applyconfigurations/api/v1/hypervisorspec.go b/applyconfigurations/api/v1/hypervisorspec.go
index 0aa2dc1..6fa5d4a 100644
--- a/applyconfigurations/api/v1/hypervisorspec.go
+++ b/applyconfigurations/api/v1/hypervisorspec.go
@@ -12,6 +12,7 @@ type HypervisorSpecApplyConfiguration struct {
SkipTests *bool `json:"skipTests,omitempty"`
CustomTraits []string `json:"customTraits,omitempty"`
Aggregates []string `json:"aggregates,omitempty"`
+ AllowedProjects []string `json:"allowedProjects,omitempty"`
HighAvailability *bool `json:"highAvailability,omitempty"`
CreateCertManagerCertificate *bool `json:"createCertManagerCertificate,omitempty"`
InstallCertificate *bool `json:"installCertificate,omitempty"`
@@ -84,6 +85,16 @@ func (b *HypervisorSpecApplyConfiguration) WithAggregates(values ...string) *Hyp
return b
}
+// WithAllowedProjects adds the given value to the AllowedProjects field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, values provided by each call will be appended to the AllowedProjects field.
+func (b *HypervisorSpecApplyConfiguration) WithAllowedProjects(values ...string) *HypervisorSpecApplyConfiguration {
+ for i := range values {
+ b.AllowedProjects = append(b.AllowedProjects, values[i])
+ }
+ return b
+}
+
// WithHighAvailability sets the HighAvailability field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the HighAvailability field is set to the value of the last call.
diff --git a/applyconfigurations/api/v1/hypervisorstatus.go b/applyconfigurations/api/v1/hypervisorstatus.go
index e51cdc9..2e12c8e 100644
--- a/applyconfigurations/api/v1/hypervisorstatus.go
+++ b/applyconfigurations/api/v1/hypervisorstatus.go
@@ -3,26 +3,30 @@
package v1
import (
+ resource "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/client-go/applyconfigurations/meta/v1"
)
// HypervisorStatusApplyConfiguration represents a declarative configuration of the HypervisorStatus type for use
// with apply.
type HypervisorStatusApplyConfiguration struct {
- LibVirtVersion *string `json:"libVirtVersion,omitempty"`
- OperatingSystem *OperatingSystemStatusApplyConfiguration `json:"operatingSystem,omitempty"`
- Update *HyperVisorUpdateStatusApplyConfiguration `json:"updateStatus,omitempty"`
- Instances []InstanceApplyConfiguration `json:"instances,omitempty"`
- Capabilities *CapabilitiesStatusApplyConfiguration `json:"capabilities,omitempty"`
- NumInstances *int `json:"numInstances,omitempty"`
- HypervisorID *string `json:"hypervisorId,omitempty"`
- ServiceID *string `json:"serviceId,omitempty"`
- Traits []string `json:"traits,omitempty"`
- Aggregates []string `json:"aggregates,omitempty"`
- InternalIP *string `json:"internalIp,omitempty"`
- Evicted *bool `json:"evicted,omitempty"`
- Conditions []metav1.ConditionApplyConfiguration `json:"conditions,omitempty"`
- SpecHash *string `json:"specHash,omitempty"`
+ LibVirtVersion *string `json:"libVirtVersion,omitempty"`
+ OperatingSystem *OperatingSystemStatusApplyConfiguration `json:"operatingSystem,omitempty"`
+ Update *HyperVisorUpdateStatusApplyConfiguration `json:"updateStatus,omitempty"`
+ Instances []InstanceApplyConfiguration `json:"instances,omitempty"`
+ Capabilities *CapabilitiesApplyConfiguration `json:"capabilities,omitempty"`
+ DomainCapabilities *DomainCapabilitiesApplyConfiguration `json:"domainCapabilities,omitempty"`
+ Capacity map[string]resource.Quantity `json:"capacity,omitempty"`
+ Allocation map[string]resource.Quantity `json:"allocation,omitempty"`
+ NumInstances *int `json:"numInstances,omitempty"`
+ HypervisorID *string `json:"hypervisorId,omitempty"`
+ ServiceID *string `json:"serviceId,omitempty"`
+ Traits []string `json:"traits,omitempty"`
+ Aggregates []string `json:"aggregates,omitempty"`
+ InternalIP *string `json:"internalIp,omitempty"`
+ Evicted *bool `json:"evicted,omitempty"`
+ Conditions []metav1.ConditionApplyConfiguration `json:"conditions,omitempty"`
+ SpecHash *string `json:"specHash,omitempty"`
}
// HypervisorStatusApplyConfiguration constructs a declarative configuration of the HypervisorStatus type for use with
@@ -71,11 +75,47 @@ func (b *HypervisorStatusApplyConfiguration) WithInstances(values ...*InstanceAp
// WithCapabilities sets the Capabilities field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Capabilities field is set to the value of the last call.
-func (b *HypervisorStatusApplyConfiguration) WithCapabilities(value *CapabilitiesStatusApplyConfiguration) *HypervisorStatusApplyConfiguration {
+func (b *HypervisorStatusApplyConfiguration) WithCapabilities(value *CapabilitiesApplyConfiguration) *HypervisorStatusApplyConfiguration {
b.Capabilities = value
return b
}
+// WithDomainCapabilities sets the DomainCapabilities field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the DomainCapabilities field is set to the value of the last call.
+func (b *HypervisorStatusApplyConfiguration) WithDomainCapabilities(value *DomainCapabilitiesApplyConfiguration) *HypervisorStatusApplyConfiguration {
+ b.DomainCapabilities = value
+ return b
+}
+
+// WithCapacity puts the entries into the Capacity field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, the entries provided by each call will be put on the Capacity field,
+// overwriting an existing map entries in Capacity field with the same key.
+func (b *HypervisorStatusApplyConfiguration) WithCapacity(entries map[string]resource.Quantity) *HypervisorStatusApplyConfiguration {
+ if b.Capacity == nil && len(entries) > 0 {
+ b.Capacity = make(map[string]resource.Quantity, len(entries))
+ }
+ for k, v := range entries {
+ b.Capacity[k] = v
+ }
+ return b
+}
+
+// WithAllocation puts the entries into the Allocation field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, the entries provided by each call will be put on the Allocation field,
+// overwriting an existing map entries in Allocation field with the same key.
+func (b *HypervisorStatusApplyConfiguration) WithAllocation(entries map[string]resource.Quantity) *HypervisorStatusApplyConfiguration {
+ if b.Allocation == nil && len(entries) > 0 {
+ b.Allocation = make(map[string]resource.Quantity, len(entries))
+ }
+ for k, v := range entries {
+ b.Allocation[k] = v
+ }
+ return b
+}
+
// WithNumInstances sets the NumInstances field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the NumInstances field is set to the value of the last call.
diff --git a/applyconfigurations/utils.go b/applyconfigurations/utils.go
index 3ecf8f6..fcaf808 100644
--- a/applyconfigurations/utils.go
+++ b/applyconfigurations/utils.go
@@ -8,7 +8,7 @@ import (
internal "github.com/cobaltcore-dev/openstack-hypervisor-operator/applyconfigurations/internal"
runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema"
- managedfields "k8s.io/apimachinery/pkg/util/managedfields"
+ "k8s.io/apimachinery/pkg/util/managedfields"
)
// ForKind returns an apply configuration type for the given GroupVersionKind, or nil if no
@@ -16,8 +16,8 @@ import (
func ForKind(kind schema.GroupVersionKind) interface{} {
switch kind {
// Group=kvm.cloud.sap, Version=v1
- case v1.SchemeGroupVersion.WithKind("CapabilitiesStatus"):
- return &apiv1.CapabilitiesStatusApplyConfiguration{}
+ case v1.SchemeGroupVersion.WithKind("Capabilities"):
+ return &apiv1.CapabilitiesApplyConfiguration{}
case v1.SchemeGroupVersion.WithKind("Eviction"):
return &apiv1.EvictionApplyConfiguration{}
case v1.SchemeGroupVersion.WithKind("EvictionSpec"):
diff --git a/charts/openstack-hypervisor-operator/crds/hypervisor-crd.yaml b/charts/openstack-hypervisor-operator/crds/hypervisor-crd.yaml
index fe36d98..1708302 100644
--- a/charts/openstack-hypervisor-operator/crds/hypervisor-crd.yaml
+++ b/charts/openstack-hypervisor-operator/crds/hypervisor-crd.yaml
@@ -109,6 +109,15 @@ spec:
items:
type: string
type: array
+ allowedProjects:
+ default: []
+ description: |-
+ AllowedProjects defines which openstack projects are allowed to schedule
+ instances on this hypervisor. The values of this list should be project
+ uuids. If left empty, all projects are allowed.
+ items:
+ type: string
+ type: array
createCertManagerCertificate:
default: false
description: |-
@@ -166,6 +175,7 @@ spec:
type: string
required:
- aggregates
+ - allowedProjects
- createCertManagerCertificate
- customTraits
- evacuateOnReboot
@@ -183,8 +193,20 @@ spec:
items:
type: string
type: array
+ allocation:
+ 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
+ default: {}
+ description: |-
+ Auto-discovered capacity currently allocated by instances
+ on the hypervisor. Note that this does not include reserved capacity.
+ type: object
capabilities:
- description: The capabilities of the hypervisors as reported by libvirt.
+ description: Auto-discovered capabilities as reported by libvirt.
properties:
cpuArch:
default: unknown
@@ -207,6 +229,19 @@ spec:
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
+ capacity:
+ 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
+ default: {}
+ description: |-
+ Auto-discovered capacity available in total on the hypervisor.
+ The remaining physical capacity can be calculated
+ as Capacity - Allocation.
+ type: object
conditions:
description: Represents the Hypervisor node conditions.
items:
@@ -264,6 +299,40 @@ spec:
- type
type: object
type: array
+ domainCapabilities:
+ description: |-
+ Auto-discovered domain capabilities relevant to check if a VM
+ can be scheduled on the hypervisor.
+ properties:
+ arch:
+ default: unknown
+ description: The available domain cpu architecture.
+ type: string
+ hypervisorType:
+ default: unknown
+ description: The supported type of virtualization for domains,
+ such as "ch".
+ type: string
+ supportedCpuModes:
+ default: []
+ description: Supported cpu modes for domains, such as "host-passthrough".
+ items:
+ type: string
+ type: array
+ supportedDevices:
+ default: []
+ description: Supported devices for domains, such as "video".
+ items:
+ type: string
+ type: array
+ supportedFeatures:
+ default: []
+ description: Supported features for domains, such as "sev" or
+ "sgx".
+ items:
+ type: string
+ type: array
+ type: object
evicted:
description: Evicted indicates whether the hypervisor is evicted.
(no instances left with active maintenance mode)
diff --git a/config/crd/bases/kvm.cloud.sap_hypervisors.yaml b/config/crd/bases/kvm.cloud.sap_hypervisors.yaml
index 311ba15..0069f2b 100644
--- a/config/crd/bases/kvm.cloud.sap_hypervisors.yaml
+++ b/config/crd/bases/kvm.cloud.sap_hypervisors.yaml
@@ -110,6 +110,15 @@ spec:
items:
type: string
type: array
+ allowedProjects:
+ default: []
+ description: |-
+ AllowedProjects defines which openstack projects are allowed to schedule
+ instances on this hypervisor. The values of this list should be project
+ uuids. If left empty, all projects are allowed.
+ items:
+ type: string
+ type: array
createCertManagerCertificate:
default: false
description: |-
@@ -167,6 +176,7 @@ spec:
type: string
required:
- aggregates
+ - allowedProjects
- createCertManagerCertificate
- customTraits
- evacuateOnReboot
@@ -184,8 +194,20 @@ spec:
items:
type: string
type: array
+ allocation:
+ 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
+ default: {}
+ description: |-
+ Auto-discovered capacity currently allocated by instances
+ on the hypervisor. Note that this does not include reserved capacity.
+ type: object
capabilities:
- description: The capabilities of the hypervisors as reported by libvirt.
+ description: Auto-discovered capabilities as reported by libvirt.
properties:
cpuArch:
default: unknown
@@ -208,6 +230,19 @@ spec:
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
+ capacity:
+ 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
+ default: {}
+ description: |-
+ Auto-discovered capacity available in total on the hypervisor.
+ The remaining physical capacity can be calculated
+ as Capacity - Allocation.
+ type: object
conditions:
description: Represents the Hypervisor node conditions.
items:
@@ -265,6 +300,40 @@ spec:
- type
type: object
type: array
+ domainCapabilities:
+ description: |-
+ Auto-discovered domain capabilities relevant to check if a VM
+ can be scheduled on the hypervisor.
+ properties:
+ arch:
+ default: unknown
+ description: The available domain cpu architecture.
+ type: string
+ hypervisorType:
+ default: unknown
+ description: The supported type of virtualization for domains,
+ such as "ch".
+ type: string
+ supportedCpuModes:
+ default: []
+ description: Supported cpu modes for domains, such as "host-passthrough".
+ items:
+ type: string
+ type: array
+ supportedDevices:
+ default: []
+ description: Supported devices for domains, such as "video".
+ items:
+ type: string
+ type: array
+ supportedFeatures:
+ default: []
+ description: Supported features for domains, such as "sev" or
+ "sgx".
+ items:
+ type: string
+ type: array
+ type: object
evicted:
description: Evicted indicates whether the hypervisor is evicted.
(no instances left with active maintenance mode)
From 52d9308090a6c6680c4710b256c51633ca41c5f8 Mon Sep 17 00:00:00 2001
From: Philipp Matthes
Date: Mon, 29 Dec 2025 12:57:49 +0100
Subject: [PATCH 2/3] Kubebuilder annotations
---
api/v1/hypervisor_types.go | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/api/v1/hypervisor_types.go b/api/v1/hypervisor_types.go
index b6bf608..91d15a3 100644
--- a/api/v1/hypervisor_types.go
+++ b/api/v1/hypervisor_types.go
@@ -210,20 +210,20 @@ type Capabilities struct {
// Domain capabilities of the hypervisor as reported by libvirt.
// These details are relevant to check if a VM can be scheduled on the hypervisor.
type DomainCapabilities struct {
- // +kubebuilder:default:=unknown
// The available domain cpu architecture.
- Arch string `json:"arch,omitempty"`
// +kubebuilder:default:=unknown
+ Arch string `json:"arch,omitempty"`
// The supported type of virtualization for domains, such as "ch".
+ // +kubebuilder:default:=unknown
HypervisorType string `json:"hypervisorType,omitempty"`
- // +kubebuilder:default:={}
// Supported devices for domains, such as "video".
- SupportedDevices []string `json:"supportedDevices,omitempty"`
// +kubebuilder:default:={}
+ SupportedDevices []string `json:"supportedDevices,omitempty"`
// Supported cpu modes for domains, such as "host-passthrough".
- SupportedCpuModes []string `json:"supportedCpuModes,omitempty"`
// +kubebuilder:default:={}
+ SupportedCpuModes []string `json:"supportedCpuModes,omitempty"`
// Supported features for domains, such as "sev" or "sgx".
+ // +kubebuilder:default:={}
SupportedFeatures []string `json:"supportedFeatures,omitempty"`
}
@@ -243,21 +243,23 @@ type HypervisorStatus struct {
Instances []Instance `json:"instances,omitempty"`
// Auto-discovered capabilities as reported by libvirt.
+ // +kubebuilder:validation:Optional
Capabilities Capabilities `json:"capabilities"`
// Auto-discovered domain capabilities relevant to check if a VM
// can be scheduled on the hypervisor.
+ // +kubebuilder:validation:Optional
DomainCapabilities DomainCapabilities `json:"domainCapabilities"`
- // +kubebuilder:default:={}
// Auto-discovered capacity available in total on the hypervisor.
// The remaining physical capacity can be calculated
// as Capacity - Allocation.
+ // +kubebuilder:default:={}
Capacity map[string]resource.Quantity `json:"capacity,omitempty"`
- // +kubebuilder:default:={}
// Auto-discovered capacity currently allocated by instances
// on the hypervisor. Note that this does not include reserved capacity.
+ // +kubebuilder:default:={}
Allocation map[string]resource.Quantity `json:"allocation,omitempty"`
// +kubebuilder:default:=0
From 37950dd7ff29f7c119ac0af9bb8c955270cf6e4c Mon Sep 17 00:00:00 2001
From: Philipp Matthes
Date: Tue, 30 Dec 2025 11:50:55 +0100
Subject: [PATCH 3/3] Add domain information list with numa cell allocation
---
api/v1/hypervisor_types.go | 80 +++++++++--
api/v1/zz_generated.deepcopy.go | 78 +++++++++--
applyconfigurations/api/v1/capabilities.go | 20 ++-
applyconfigurations/api/v1/cell.go | 42 ++++++
applyconfigurations/api/v1/domaininfo.go | 73 ++++++++++
.../api/v1/hypervisorstatus.go | 35 ++---
.../crds/hypervisor-crd.yaml | 129 ++++++++++++++----
.../crd/bases/kvm.cloud.sap_hypervisors.yaml | 129 ++++++++++++++----
8 files changed, 476 insertions(+), 110 deletions(-)
create mode 100644 applyconfigurations/api/v1/cell.go
create mode 100644 applyconfigurations/api/v1/domaininfo.go
diff --git a/api/v1/hypervisor_types.go b/api/v1/hypervisor_types.go
index 91d15a3..a2d1a0b 100644
--- a/api/v1/hypervisor_types.go
+++ b/api/v1/hypervisor_types.go
@@ -196,6 +196,15 @@ type OperatingSystemStatus struct {
GardenLinuxFeatures []string `json:"gardenLinuxFeatures,omitempty"`
}
+// Cell represents a single cell of the host's topology.
+type Cell struct {
+ // ID is the identifier of the cell.
+ ID int `json:"id"`
+ // The cell's capacity, such as the number of cpus, memory, and hugepages.
+ // +kubebuilder:default:={}
+ Capacity map[string]resource.Quantity `json:"capacity,omitempty"`
+}
+
// Capabilities of the hypervisor as reported by libvirt.
type Capabilities struct {
// +kubebuilder:default:=unknown
@@ -205,6 +214,9 @@ type Capabilities struct {
HostMemory resource.Quantity `json:"memory,omitempty"`
// Total host cpus available as a sum of cpus over all numa cells.
HostCpus resource.Quantity `json:"cpus,omitempty"`
+ // The host's cell topology (a.k.a. numa cells).
+ // +kubebuilder:validation:Optional
+ HostTopology []Cell `json:"hostTopology,omitempty"`
}
// Domain capabilities of the hypervisor as reported by libvirt.
@@ -213,20 +225,73 @@ type DomainCapabilities struct {
// The available domain cpu architecture.
// +kubebuilder:default:=unknown
Arch string `json:"arch,omitempty"`
+
// The supported type of virtualization for domains, such as "ch".
// +kubebuilder:default:=unknown
HypervisorType string `json:"hypervisorType,omitempty"`
- // Supported devices for domains, such as "video".
+
+ // Supported devices for domains.
+ //
+ // The format of this list is the device type, and if specified, a specific
+ // model. For example, the take the following xml domain device definition:
+ //
+ //
+ //
+ // The corresponding entries in this list would be "video" and "video/nvidia".
+ //
// +kubebuilder:default:={}
SupportedDevices []string `json:"supportedDevices,omitempty"`
- // Supported cpu modes for domains, such as "host-passthrough".
+
+ // Supported cpu modes for domains.
+ //
+ // The format of this list is cpu mode, and if specified, a specific
+ // submode. For example, the take the following xml domain cpu definition:
+ //
+ //
+ //
+ //
+ //
+ // The corresponding entries in this list would be "host-passthrough" and
+ // "host-passthrough/migratable".
+ //
// +kubebuilder:default:={}
SupportedCpuModes []string `json:"supportedCpuModes,omitempty"`
+
// Supported features for domains, such as "sev" or "sgx".
+ //
+ // This is a flat list of supported features, meaning the following xml:
+ //
+ //
+ //
+ //
+ //
+ //
+ // Would correspond to the entries "sev" and "sgx" in this list.
+ //
// +kubebuilder:default:={}
SupportedFeatures []string `json:"supportedFeatures,omitempty"`
}
+// Domain information as reported by libvirt.
+type DomainInfo struct {
+ // Name is the name of the domain.
+ Name string `json:"name"`
+ // UUID is the uuid of the domain.
+ UUID string `json:"uuid"`
+ // Resource allocation of the domain.
+ // This can include memory, cpu, and other.
+ Allocation map[string]resource.Quantity `json:"allocation,omitempty"`
+ // The memory numa cells of the domain, derived from the numa tune.
+ MemoryCells []int `json:"memoryCells,omitempty"`
+ // The cpu numa cells of the domain, derived from the numa information
+ // of the cpu mode.
+ CpuCells []int `json:"cpuCells,omitempty"`
+}
+
// HypervisorStatus defines the observed state of Hypervisor
type HypervisorStatus struct {
// +kubebuilder:default:=unknown
@@ -251,16 +316,9 @@ type HypervisorStatus struct {
// +kubebuilder:validation:Optional
DomainCapabilities DomainCapabilities `json:"domainCapabilities"`
- // Auto-discovered capacity available in total on the hypervisor.
- // The remaining physical capacity can be calculated
- // as Capacity - Allocation.
+ // Auto-discovered domain infos as reported by libvirt (dumpxml).
// +kubebuilder:default:={}
- Capacity map[string]resource.Quantity `json:"capacity,omitempty"`
-
- // Auto-discovered capacity currently allocated by instances
- // on the hypervisor. Note that this does not include reserved capacity.
- // +kubebuilder:default:={}
- Allocation map[string]resource.Quantity `json:"allocation,omitempty"`
+ DomainInfos []DomainInfo `json:"domainInfos,omitempty"`
// +kubebuilder:default:=0
// Represent the num of instances
diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go
index 7336a32..d41ee12 100644
--- a/api/v1/zz_generated.deepcopy.go
+++ b/api/v1/zz_generated.deepcopy.go
@@ -32,6 +32,13 @@ func (in *Capabilities) DeepCopyInto(out *Capabilities) {
*out = *in
out.HostMemory = in.HostMemory.DeepCopy()
out.HostCpus = in.HostCpus.DeepCopy()
+ if in.HostTopology != nil {
+ in, out := &in.HostTopology, &out.HostTopology
+ *out = make([]Cell, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Capabilities.
@@ -44,6 +51,28 @@ func (in *Capabilities) DeepCopy() *Capabilities {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Cell) DeepCopyInto(out *Cell) {
+ *out = *in
+ if in.Capacity != nil {
+ in, out := &in.Capacity, &out.Capacity
+ *out = make(map[string]resource.Quantity, len(*in))
+ for key, val := range *in {
+ (*out)[key] = val.DeepCopy()
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Cell.
+func (in *Cell) DeepCopy() *Cell {
+ if in == nil {
+ return nil
+ }
+ out := new(Cell)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DomainCapabilities) DeepCopyInto(out *DomainCapabilities) {
*out = *in
@@ -74,6 +103,38 @@ func (in *DomainCapabilities) DeepCopy() *DomainCapabilities {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *DomainInfo) DeepCopyInto(out *DomainInfo) {
+ *out = *in
+ if in.Allocation != nil {
+ in, out := &in.Allocation, &out.Allocation
+ *out = make(map[string]resource.Quantity, len(*in))
+ for key, val := range *in {
+ (*out)[key] = val.DeepCopy()
+ }
+ }
+ if in.MemoryCells != nil {
+ in, out := &in.MemoryCells, &out.MemoryCells
+ *out = make([]int, len(*in))
+ copy(*out, *in)
+ }
+ if in.CpuCells != nil {
+ in, out := &in.CpuCells, &out.CpuCells
+ *out = make([]int, len(*in))
+ copy(*out, *in)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DomainInfo.
+func (in *DomainInfo) DeepCopy() *DomainInfo {
+ if in == nil {
+ return nil
+ }
+ out := new(DomainInfo)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Eviction) DeepCopyInto(out *Eviction) {
*out = *in
@@ -291,18 +352,11 @@ func (in *HypervisorStatus) DeepCopyInto(out *HypervisorStatus) {
}
in.Capabilities.DeepCopyInto(&out.Capabilities)
in.DomainCapabilities.DeepCopyInto(&out.DomainCapabilities)
- if in.Capacity != nil {
- in, out := &in.Capacity, &out.Capacity
- *out = make(map[string]resource.Quantity, len(*in))
- for key, val := range *in {
- (*out)[key] = val.DeepCopy()
- }
- }
- if in.Allocation != nil {
- in, out := &in.Allocation, &out.Allocation
- *out = make(map[string]resource.Quantity, len(*in))
- for key, val := range *in {
- (*out)[key] = val.DeepCopy()
+ if in.DomainInfos != nil {
+ in, out := &in.DomainInfos, &out.DomainInfos
+ *out = make([]DomainInfo, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Traits != nil {
diff --git a/applyconfigurations/api/v1/capabilities.go b/applyconfigurations/api/v1/capabilities.go
index 7b87dd8..57d6da5 100644
--- a/applyconfigurations/api/v1/capabilities.go
+++ b/applyconfigurations/api/v1/capabilities.go
@@ -9,9 +9,10 @@ import (
// CapabilitiesApplyConfiguration represents a declarative configuration of the Capabilities type for use
// with apply.
type CapabilitiesApplyConfiguration struct {
- HostCpuArch *string `json:"cpuArch,omitempty"`
- HostMemory *resource.Quantity `json:"memory,omitempty"`
- HostCpus *resource.Quantity `json:"cpus,omitempty"`
+ HostCpuArch *string `json:"cpuArch,omitempty"`
+ HostMemory *resource.Quantity `json:"memory,omitempty"`
+ HostCpus *resource.Quantity `json:"cpus,omitempty"`
+ HostTopology []CellApplyConfiguration `json:"hostTopology,omitempty"`
}
// CapabilitiesApplyConfiguration constructs a declarative configuration of the Capabilities type for use with
@@ -43,3 +44,16 @@ func (b *CapabilitiesApplyConfiguration) WithHostCpus(value resource.Quantity) *
b.HostCpus = &value
return b
}
+
+// WithHostTopology adds the given value to the HostTopology field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, values provided by each call will be appended to the HostTopology field.
+func (b *CapabilitiesApplyConfiguration) WithHostTopology(values ...*CellApplyConfiguration) *CapabilitiesApplyConfiguration {
+ for i := range values {
+ if values[i] == nil {
+ panic("nil value passed to WithHostTopology")
+ }
+ b.HostTopology = append(b.HostTopology, *values[i])
+ }
+ return b
+}
diff --git a/applyconfigurations/api/v1/cell.go b/applyconfigurations/api/v1/cell.go
new file mode 100644
index 0000000..e749966
--- /dev/null
+++ b/applyconfigurations/api/v1/cell.go
@@ -0,0 +1,42 @@
+// Code generated by controller-gen. DO NOT EDIT.
+
+package v1
+
+import (
+ resource "k8s.io/apimachinery/pkg/api/resource"
+)
+
+// CellApplyConfiguration represents a declarative configuration of the Cell type for use
+// with apply.
+type CellApplyConfiguration struct {
+ ID *int `json:"id,omitempty"`
+ Capacity map[string]resource.Quantity `json:"capacity,omitempty"`
+}
+
+// CellApplyConfiguration constructs a declarative configuration of the Cell type for use with
+// apply.
+func Cell() *CellApplyConfiguration {
+ return &CellApplyConfiguration{}
+}
+
+// WithID sets the ID field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the ID field is set to the value of the last call.
+func (b *CellApplyConfiguration) WithID(value int) *CellApplyConfiguration {
+ b.ID = &value
+ return b
+}
+
+// WithCapacity puts the entries into the Capacity field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, the entries provided by each call will be put on the Capacity field,
+// overwriting an existing map entries in Capacity field with the same key.
+func (b *CellApplyConfiguration) WithCapacity(entries map[string]resource.Quantity) *CellApplyConfiguration {
+ if b.Capacity == nil && len(entries) > 0 {
+ b.Capacity = make(map[string]resource.Quantity, len(entries))
+ }
+ for k, v := range entries {
+ b.Capacity[k] = v
+ }
+ return b
+}
diff --git a/applyconfigurations/api/v1/domaininfo.go b/applyconfigurations/api/v1/domaininfo.go
new file mode 100644
index 0000000..b521f81
--- /dev/null
+++ b/applyconfigurations/api/v1/domaininfo.go
@@ -0,0 +1,73 @@
+// Code generated by controller-gen. DO NOT EDIT.
+
+package v1
+
+import (
+ resource "k8s.io/apimachinery/pkg/api/resource"
+)
+
+// DomainInfoApplyConfiguration represents a declarative configuration of the DomainInfo type for use
+// with apply.
+type DomainInfoApplyConfiguration struct {
+ Name *string `json:"name,omitempty"`
+ UUID *string `json:"uuid,omitempty"`
+ Allocation map[string]resource.Quantity `json:"allocation,omitempty"`
+ MemoryCells []int `json:"memoryCells,omitempty"`
+ CpuCells []int `json:"cpuCells,omitempty"`
+}
+
+// DomainInfoApplyConfiguration constructs a declarative configuration of the DomainInfo type for use with
+// apply.
+func DomainInfo() *DomainInfoApplyConfiguration {
+ return &DomainInfoApplyConfiguration{}
+}
+
+// WithName sets the Name field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the Name field is set to the value of the last call.
+func (b *DomainInfoApplyConfiguration) WithName(value string) *DomainInfoApplyConfiguration {
+ b.Name = &value
+ return b
+}
+
+// WithUUID sets the UUID field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the UUID field is set to the value of the last call.
+func (b *DomainInfoApplyConfiguration) WithUUID(value string) *DomainInfoApplyConfiguration {
+ b.UUID = &value
+ return b
+}
+
+// WithAllocation puts the entries into the Allocation field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, the entries provided by each call will be put on the Allocation field,
+// overwriting an existing map entries in Allocation field with the same key.
+func (b *DomainInfoApplyConfiguration) WithAllocation(entries map[string]resource.Quantity) *DomainInfoApplyConfiguration {
+ if b.Allocation == nil && len(entries) > 0 {
+ b.Allocation = make(map[string]resource.Quantity, len(entries))
+ }
+ for k, v := range entries {
+ b.Allocation[k] = v
+ }
+ return b
+}
+
+// WithMemoryCells adds the given value to the MemoryCells field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, values provided by each call will be appended to the MemoryCells field.
+func (b *DomainInfoApplyConfiguration) WithMemoryCells(values ...int) *DomainInfoApplyConfiguration {
+ for i := range values {
+ b.MemoryCells = append(b.MemoryCells, values[i])
+ }
+ return b
+}
+
+// WithCpuCells adds the given value to the CpuCells field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, values provided by each call will be appended to the CpuCells field.
+func (b *DomainInfoApplyConfiguration) WithCpuCells(values ...int) *DomainInfoApplyConfiguration {
+ for i := range values {
+ b.CpuCells = append(b.CpuCells, values[i])
+ }
+ return b
+}
diff --git a/applyconfigurations/api/v1/hypervisorstatus.go b/applyconfigurations/api/v1/hypervisorstatus.go
index 2e12c8e..a82dcf0 100644
--- a/applyconfigurations/api/v1/hypervisorstatus.go
+++ b/applyconfigurations/api/v1/hypervisorstatus.go
@@ -3,7 +3,6 @@
package v1
import (
- resource "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/client-go/applyconfigurations/meta/v1"
)
@@ -16,8 +15,7 @@ type HypervisorStatusApplyConfiguration struct {
Instances []InstanceApplyConfiguration `json:"instances,omitempty"`
Capabilities *CapabilitiesApplyConfiguration `json:"capabilities,omitempty"`
DomainCapabilities *DomainCapabilitiesApplyConfiguration `json:"domainCapabilities,omitempty"`
- Capacity map[string]resource.Quantity `json:"capacity,omitempty"`
- Allocation map[string]resource.Quantity `json:"allocation,omitempty"`
+ DomainInfos []DomainInfoApplyConfiguration `json:"domainInfos,omitempty"`
NumInstances *int `json:"numInstances,omitempty"`
HypervisorID *string `json:"hypervisorId,omitempty"`
ServiceID *string `json:"serviceId,omitempty"`
@@ -88,30 +86,15 @@ func (b *HypervisorStatusApplyConfiguration) WithDomainCapabilities(value *Domai
return b
}
-// WithCapacity puts the entries into the Capacity field in the declarative configuration
+// WithDomainInfos adds the given value to the DomainInfos field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
-// If called multiple times, the entries provided by each call will be put on the Capacity field,
-// overwriting an existing map entries in Capacity field with the same key.
-func (b *HypervisorStatusApplyConfiguration) WithCapacity(entries map[string]resource.Quantity) *HypervisorStatusApplyConfiguration {
- if b.Capacity == nil && len(entries) > 0 {
- b.Capacity = make(map[string]resource.Quantity, len(entries))
- }
- for k, v := range entries {
- b.Capacity[k] = v
- }
- return b
-}
-
-// WithAllocation puts the entries into the Allocation field in the declarative configuration
-// and returns the receiver, so that objects can be build by chaining "With" function invocations.
-// If called multiple times, the entries provided by each call will be put on the Allocation field,
-// overwriting an existing map entries in Allocation field with the same key.
-func (b *HypervisorStatusApplyConfiguration) WithAllocation(entries map[string]resource.Quantity) *HypervisorStatusApplyConfiguration {
- if b.Allocation == nil && len(entries) > 0 {
- b.Allocation = make(map[string]resource.Quantity, len(entries))
- }
- for k, v := range entries {
- b.Allocation[k] = v
+// If called multiple times, values provided by each call will be appended to the DomainInfos field.
+func (b *HypervisorStatusApplyConfiguration) WithDomainInfos(values ...*DomainInfoApplyConfiguration) *HypervisorStatusApplyConfiguration {
+ for i := range values {
+ if values[i] == nil {
+ panic("nil value passed to WithDomainInfos")
+ }
+ b.DomainInfos = append(b.DomainInfos, *values[i])
}
return b
}
diff --git a/charts/openstack-hypervisor-operator/crds/hypervisor-crd.yaml b/charts/openstack-hypervisor-operator/crds/hypervisor-crd.yaml
index 1708302..f8b5bf4 100644
--- a/charts/openstack-hypervisor-operator/crds/hypervisor-crd.yaml
+++ b/charts/openstack-hypervisor-operator/crds/hypervisor-crd.yaml
@@ -193,18 +193,6 @@ spec:
items:
type: string
type: array
- allocation:
- 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
- default: {}
- description: |-
- Auto-discovered capacity currently allocated by instances
- on the hypervisor. Note that this does not include reserved capacity.
- type: object
capabilities:
description: Auto-discovered capabilities as reported by libvirt.
properties:
@@ -220,6 +208,29 @@ spec:
numa cells.
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
+ hostTopology:
+ description: The host's cell topology (a.k.a. numa cells).
+ items:
+ description: Cell represents a single cell of the host's topology.
+ properties:
+ capacity:
+ 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
+ default: {}
+ description: The cell's capacity, such as the number of
+ cpus, memory, and hugepages.
+ type: object
+ id:
+ description: ID is the identifier of the cell.
+ type: integer
+ required:
+ - id
+ type: object
+ type: array
memory:
anyOf:
- type: integer
@@ -229,19 +240,6 @@ spec:
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
- capacity:
- 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
- default: {}
- description: |-
- Auto-discovered capacity available in total on the hypervisor.
- The remaining physical capacity can be calculated
- as Capacity - Allocation.
- type: object
conditions:
description: Represents the Hypervisor node conditions.
items:
@@ -315,24 +313,97 @@ spec:
type: string
supportedCpuModes:
default: []
- description: Supported cpu modes for domains, such as "host-passthrough".
+ description: |-
+ Supported cpu modes for domains.
+
+ The format of this list is cpu mode, and if specified, a specific
+ submode. For example, the take the following xml domain cpu definition:
+
+
+
+
+
+ The corresponding entries in this list would be "host-passthrough" and
+ "host-passthrough/migratable".
items:
type: string
type: array
supportedDevices:
default: []
- description: Supported devices for domains, such as "video".
+ description: |-
+ Supported devices for domains.
+
+ The format of this list is the device type, and if specified, a specific
+ model. For example, the take the following xml domain device definition:
+
+
+
+ The corresponding entries in this list would be "video" and "video/nvidia".
items:
type: string
type: array
supportedFeatures:
default: []
- description: Supported features for domains, such as "sev" or
- "sgx".
+ description: |-
+ Supported features for domains, such as "sev" or "sgx".
+
+ This is a flat list of supported features, meaning the following xml:
+
+
+
+
+
+
+ Would correspond to the entries "sev" and "sgx" in this list.
items:
type: string
type: array
type: object
+ domainInfos:
+ default: []
+ description: Auto-discovered domain infos as reported by libvirt (dumpxml).
+ items:
+ description: Domain information as reported by libvirt.
+ properties:
+ allocation:
+ 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: |-
+ Resource allocation of the domain.
+ This can include memory, cpu, and other.
+ type: object
+ cpuCells:
+ description: |-
+ The cpu numa cells of the domain, derived from the numa information
+ of the cpu mode.
+ items:
+ type: integer
+ type: array
+ memoryCells:
+ description: The memory numa cells of the domain, derived from
+ the numa tune.
+ items:
+ type: integer
+ type: array
+ name:
+ description: Name is the name of the domain.
+ type: string
+ uuid:
+ description: UUID is the uuid of the domain.
+ type: string
+ required:
+ - name
+ - uuid
+ type: object
+ type: array
evicted:
description: Evicted indicates whether the hypervisor is evicted.
(no instances left with active maintenance mode)
diff --git a/config/crd/bases/kvm.cloud.sap_hypervisors.yaml b/config/crd/bases/kvm.cloud.sap_hypervisors.yaml
index 0069f2b..056cfcf 100644
--- a/config/crd/bases/kvm.cloud.sap_hypervisors.yaml
+++ b/config/crd/bases/kvm.cloud.sap_hypervisors.yaml
@@ -194,18 +194,6 @@ spec:
items:
type: string
type: array
- allocation:
- 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
- default: {}
- description: |-
- Auto-discovered capacity currently allocated by instances
- on the hypervisor. Note that this does not include reserved capacity.
- type: object
capabilities:
description: Auto-discovered capabilities as reported by libvirt.
properties:
@@ -221,6 +209,29 @@ spec:
numa cells.
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
+ hostTopology:
+ description: The host's cell topology (a.k.a. numa cells).
+ items:
+ description: Cell represents a single cell of the host's topology.
+ properties:
+ capacity:
+ 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
+ default: {}
+ description: The cell's capacity, such as the number of
+ cpus, memory, and hugepages.
+ type: object
+ id:
+ description: ID is the identifier of the cell.
+ type: integer
+ required:
+ - id
+ type: object
+ type: array
memory:
anyOf:
- type: integer
@@ -230,19 +241,6 @@ spec:
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
- capacity:
- 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
- default: {}
- description: |-
- Auto-discovered capacity available in total on the hypervisor.
- The remaining physical capacity can be calculated
- as Capacity - Allocation.
- type: object
conditions:
description: Represents the Hypervisor node conditions.
items:
@@ -316,24 +314,97 @@ spec:
type: string
supportedCpuModes:
default: []
- description: Supported cpu modes for domains, such as "host-passthrough".
+ description: |-
+ Supported cpu modes for domains.
+
+ The format of this list is cpu mode, and if specified, a specific
+ submode. For example, the take the following xml domain cpu definition:
+
+
+
+
+
+ The corresponding entries in this list would be "host-passthrough" and
+ "host-passthrough/migratable".
items:
type: string
type: array
supportedDevices:
default: []
- description: Supported devices for domains, such as "video".
+ description: |-
+ Supported devices for domains.
+
+ The format of this list is the device type, and if specified, a specific
+ model. For example, the take the following xml domain device definition:
+
+
+
+ The corresponding entries in this list would be "video" and "video/nvidia".
items:
type: string
type: array
supportedFeatures:
default: []
- description: Supported features for domains, such as "sev" or
- "sgx".
+ description: |-
+ Supported features for domains, such as "sev" or "sgx".
+
+ This is a flat list of supported features, meaning the following xml:
+
+
+
+
+
+
+ Would correspond to the entries "sev" and "sgx" in this list.
items:
type: string
type: array
type: object
+ domainInfos:
+ default: []
+ description: Auto-discovered domain infos as reported by libvirt (dumpxml).
+ items:
+ description: Domain information as reported by libvirt.
+ properties:
+ allocation:
+ 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: |-
+ Resource allocation of the domain.
+ This can include memory, cpu, and other.
+ type: object
+ cpuCells:
+ description: |-
+ The cpu numa cells of the domain, derived from the numa information
+ of the cpu mode.
+ items:
+ type: integer
+ type: array
+ memoryCells:
+ description: The memory numa cells of the domain, derived from
+ the numa tune.
+ items:
+ type: integer
+ type: array
+ name:
+ description: Name is the name of the domain.
+ type: string
+ uuid:
+ description: UUID is the uuid of the domain.
+ type: string
+ required:
+ - name
+ - uuid
+ type: object
+ type: array
evicted:
description: Evicted indicates whether the hypervisor is evicted.
(no instances left with active maintenance mode)