Skip to content

Nova epoxy upgrade batch 2#637

Merged
leust merged 92 commits into
stable/2025.1-m3from
nova-epoxy-upgrade-batch-2
Jul 2, 2026
Merged

Nova epoxy upgrade batch 2#637
leust merged 92 commits into
stable/2025.1-m3from
nova-epoxy-upgrade-batch-2

Conversation

@leust

@leust leust commented Jul 2, 2026

Copy link
Copy Markdown

No description provided.

joker-at-work and others added 30 commits July 2, 2026 10:54
"nova-manage placement sync_aggregates" doesn't support Ironic hosts,
because they have multiple compute nodes. In general, Nova doesn't
support aggregates for Ironic hosts. But we still use them for assigning
an availability zone to a rack (a building block) of nodes grouped into
a Nova host.

Therefore, we patch above-mentioned command to handle a list of (in most
cases one) compute node UUIDs, only erroring out if the host we find
multiple compute nodes for doesn't look like an Ironic host (based on
having "ironic" in the name).

There can be Ironic hosts, that only have nodes assigned when those
nodes are getting repairs or getting build up. Those Ironic hosts would
come up empty when searching for ComputeNodes in the sync_aggregates
command and would be reported as a problem, which makes the command
fail with exit-code 5. Since it's no problem if an Ironic Host doesn't
have a ComputeNode, because each node is its own resource provider in
placement anyways, we ignore Ironic hosts without nodes now in the
error-reporting.

Change-Id: I4f7e5fd82c51ce5d6f42089beb5a70e469ec54df
Incorporated-Change-Id: I163f3e46f2e375531b870a363b84bba67816954d
(cherry picked from commit f899a7c)
Change-Id: I117a4d97ff7e901ce9b590f04a40e58053f0e845
(cherry picked from commit a39dd17)
We expose a capability "resource_scheduling" which enables the
`ComputeManager` to decide whether to allow multiple VMs on the same
host in the post-scheduling check.

We also update the DRS rules when spawning/resizing/migrating a VM.

"soft-affinity" is excluded from DRS rule creation and thus only works
on cluster-level not on HV-level. The reason is, that DRS doesn't know
about "soft" and will require the VMs to run on the same ESXi. Having
the VMs run inside the same rack should be good-enough though.

For managing DRS settings, we introduce a new module `cluster_util` to
the `vmwareapi` driver.

Change-Id: Iba9706b7353575fd3f5df5e903e3f254c5e49d73
Co-Authored-By: Johannes Kulik <johannes.kulik@sap.com>
Co-Authored-By: Fabian Wiesel <fabian.wiesel@sap.com>
Incorporated-Change-Id: I6d44910c420de4c76b6112904ccfebe3ec923098
(cherry picked from commit d1b19da)
We still have to old `_create_vm_group_spec()` to get the same behavior,
but nobody outside of `cluster_util` uses it. The new functions
`create_vm_group()`, `create_host_group()` and `create_group_spec()`
expose a clearer interface and make it possible to overwrite hosts/vms
instead of just appending to existing ones. This will be useful if
customers can upgrade server-groups via API.

Change-Id: I5444318994ac7929a24d357fabb8133410d5bd9d
(cherry picked from commit 27a9012)
(cherry picked from commit d945c77)
This splits up functionality for creating rules between VMs into
`create_vm_rule()` and `create_rule_spec()` and thus enables us to use
it more controlled also from the outside, e.g. in the upcoming sync loop
for server-groups.

Since DRS ignores the "mandatory" attribute for VM-VM rules, we remove
setting it here, so it doesn't look like changing the value would make a
difference.

Change-Id: Ib515e02226e674d0f7cbdc3c354ade5cd77a0b8c
(cherry picked from commit 9386f11)
(cherry picked from commit 03232ab)
We will need this in the sync-loop after customers are enabled to change
server-group memebers via API.

Change-Id: I5e7f27251b6f2c09002445d6c374f887864ea19f
(cherry picked from commit 3f27feb)
(cherry picked from commit aa9a0be)
We will need this in the sync-loop after customers are enabled to change
server-group members via API.

Change-Id: Id2fbaa67b799e370331472ecccc79d99dd07e01f
Incorporated-Change-Id: I443338bf97dcf83478e0a9971179480ecb01c009
(cherry picked from commit eafa794)
(cherry picked from commit e219cf2)
We need to know the compute host to query the instances from the API for
sync_server_group(), so we save it onto the VMwareVMOps instance when
the VMwareVCDriver instance receives it in the init_host() call.

Change-Id: I473539000dde4629e2a251cd9145c8047ce60a41
(cherry picked from commit 22ab4cb)
(cherry picked from commit e925801)
We want to create a sync-loop for applying/removing server-groups
changed by the user via API. For this we need to be able to distinguish
between driver-created DRS groups/rules and admin-created ones. To do
this, we introduce a prefix for the DRS group/rule name, which will work
as an identifier later on.

Since we're now using not only a UUID, but a UUID with a prefix, we
change GroupInfo to have a "name" attribute instead of a "uuid"
attribute.

As we're changing how DRS groups/rules look, we need a migration to run
before deploying this to production.

Change-Id: I07ecd1953a85d0f53082fa9b0c49b80c2c9bf9d3
(cherry picked from commit 7984cae)
(cherry picked from commit 1e5e590)
It was previously used when deleting empty DRS groups.

Change-Id: I82612decf3938285c43f5e97abb48da349ad3fba
(cherry picked from commit 8e0836d)
(cherry picked from commit 63ec87b)
This function is able to add/remove DRS overrides for a VM. DRS
overrides can be used to set an explicit behaviour for a VM that can
differ from the default of the cluster.

Change-Id: I9022869ad546e28ec9de66e17d639c3314b19832
(cherry picked from commit e3e44a4)
The DRS rules created by Nova do not use those VmGroups and they don't
seem to server a purpose otherwise. Therfore, we only update/create a
VmGroup that's not based on a server-group, i.e. an admin-defined group.
We currently only have this kind of group for the special_spawning
case to support a free host for big VMs.

Change-Id: Ide011e157ad46037304cfdb52b1db397dde38cc8
(cherry picked from commit 8c3640b)
(cherry picked from commit 0f0df08)
Since we don't create new ones, we also don't have to keep track of
empty ones. Instead, we will just delete all the VmGroups once via an
external script.

Change-Id: I88baeadcea3a7bfe946596b169bc3abe6798d9d6
(cherry picked from commit 89dcef0)
(cherry picked from commit e4b85ba)
These functions are simple helper functions to create, update and delete
a DRS rule, so we have to code necessary for that at a single place.

Change-Id: I44aeed6f99b9803adca0062b2d7b12cc2e295f03
Incorporated-Change-Id: I86f7ca85d9b0edc1406a54a6f392bfff8f0af00d
(cherry picked from commit 94f8c7a)
The VMware driver supports syncing server-groups as DRS rules into the
cluster managed by the nova-compute node. The method will be called when
a user updates a server-group via API and will later get reused when
spawning a VM, too.

Instances in certain states need to be excluded from the sync for
multiple reasons:
1) when instances are going away during the sync, this can lead to an
error
2) VMs contained in a DRS rule cannot be vMotioned - excluding them makes
it easier for the live-migration code to update the cluster
appropriately

We do not sync "soft-affinity" server-groups, mainly because we use
"soft-affinity" is our way to give customers the possibility to end up
on the same cluster, without the need to end up on the same host, too.
We also cannot implement the "soft" part currently and thus spawning a
VM will fail if the host is too full, as there are no non-mandatory
VM-to-VM rules in VMware DRS.

We might be able to optimize it a little more, by keeping a local list
of DRS rules instead of querying the cluster in real-time. Tests have
shown, that it takes < 500ms to query the cluster, though.

Change-Id: I534c035a1e2d962cf5d187d56d104e743f7ade15
Incorporated-Change-Id: I8bc94aebebcd878f60c33fe009f048afeb9a42c0
Incorporated-Change-Id: I745ac6616eefd193ce8c7a9a5cba3c68fc59ac75
(cherry picked from commit 52f42fc)
(cherry picked from commit 70aca2b)
Searching for a list of instance groups belonging to a list of instances
can be helpful for checking if a server-group update is valid and maybe
if a nova-compute wants to sync down server-groups like the VMware HV is
able to.

Change-Id: Iec93becf0299ec0617e99ce16c06e37c84cb33ee
(cherry picked from commit 838142b)
(cherry picked from commit 243275e)
We're going to change the API to allow updates of server-group members
and need to trigger a sync in the backend, whenever such a change
occurs. Therefore, we need a bunch of methods going through the whole
stack to call the driver.

We use a cast and not a call here, because we cannot let the API wait
for all of this to happen. If the cast gets lost somehow, a sync-loop
implemented in the driver will pick the change up, eventually

The API will have to supply a list of hosts to call, so we only sync the
group on the necessary hosts.

Change-Id: I00e012ed52ba9fd36b094ecf2dc86b023f2f5a21
(cherry picked from commit f3d2ad7)
(cherry picked from commit ae57baa)
This function wasn't previously available, because - as the removed
comment says - there was no user-facing API that would allow removal of
instance group members. Since we plan on changing the API, we need to
add a pulic method.

Adding this method, we also need to send notifications like we do for
"add_members()" and thus added the appropriate functionality.

Change-Id: I4270212b57782e5ffeaf69dc3bd57c7c60a7ffe5
(cherry picked from commit df3bd90)
(cherry picked from commit e7c9a01)
In case we missed an update to a server-group, we want to be able to
recover at some point in time. Therefore, we implement a sync-loop to
call the driver's sync_server_group() for every server-group UUID we
find as belonging to our host and also for every DRS rule we find.

Since we only start the sync-loop for server-groups once on startup, we
have to make it resistant against any exceptions - e.g. if the DB is
unreachable for a time or the vCenter is unreachable at the time.

Change-Id: I9a633dc87ad1aab7d5f00e5143fac97dd3b87176
Incorporated-Change-Id: I74036b6bfc449b407f687afac1ba4365bcbdc2ee
(cherry picked from commit 583b1fd)
(cherry picked from commit 4a58936)
We can use sync_server_group() in update_cluster_placement() to use the
same mechanism that's used when a user edits a server-group in the DB.
This makes sure, that a DRS rule is only created, if it has more than 1
members and also syncs in the other member in case the newly-spawned
instance is the second member.

Change-Id: I62c1ae3d897f5ccda8788a4d4b23e553be8bc5cf
(cherry picked from commit 2dd55ea)
(cherry picked from commit f82c01f)
When retrieving multiple - or all - server groups, the code tries to
find not deleted members for each server group in every cell
individually. This is highly inefficient, which is especially noticable
when the number of server groups rises.

We change this to query all members of all server-groups we will reply
with (i.e. from the already limited list) in advance and pass this set
of existing uuids into the function formatting the server group. This is
more efficient, because we only do one large query instead of up to 1000
times the number of cells.

Change-Id: I3459ce7a8bec9a9e6f3a3b496a3e441078b86af0
(cherry picked from commit e676dd1)
(cherry picked from commit f216de6)
We exted "server_groups._get_not_deleted()" function to return a
dictionary of instance UUID to host mapping. This is a preliminary step
to introducing an update of the server-groups, which will need both the
instance UUIDs and the hosts to filter out to-be-removed instances and
check the validity of the policy when adding instances.

We cannot use "InstanceGroup.get_hosts()" for this, as it's not
cell-aware and thus extend this function instead.

TODO:
	* tests

Change-Id: I253ef54560c2422baec187b350f05b1b2affc34e
(cherry picked from commit a94f6f7)
(cherry picked from commit 0b38c20)
This new API endpoint allows to add and/or remove members from a
server-group. We found this to be necessary, because instances might get
created without a server-group, but later need an HA-partner and
re-installing would mean downtime or too much effort.

The endpoint checks the validity of the policy is still given after all
changes are done and strives for idempotency in that it allows
removal/addition of already removed/added instance uuids to accommodate
for requests built in parallel.

We do not allow a server to join a second server-group if it already
joined one. The whole change to the server-group is errored out if any
of the servers are already in another group to make it easier in
validation and either apply the whole change requested by the user or
nothing.

When we add/remove a server to/from a server-group, we have to update
the server's RequestSpec's `instance_group` attribute, because this is
used during scheduling when resizing a server to record a list of
appropriate hosts for the instance.

Only members/admins can change the server-groups.

TODO:
	* api-request docs

Change-Id: I30d5d1dc3a41553b4336aad3877018989159495c
Incorporated-Change-Id: Ibc78cbd80ae49df9be60f6d9eda56a47d9ffe39e
Incorporated-Change-Id: I6a06e4b4a8c22737c20ab51e85ceb2bf98082b26
Incorporated-Change-Id: Ic193dd3c59bc717ba5329f63054297f44127d76d
Co-Authored-By: Jakob Karge <jakob.karge@sap.com>
(cherry picked from commit aec6f6e)
Instead of getting all instance groups from DB and after then limit the
results with common.limited, we added limit and offset parameters to
_instance_group_get_query function to limit the database query itself.

SQLAlchemy throws an exception when applying a filter to the query
after setting limits and offset that's why project_id parameter added to
 _instance_group_get_query.

Change-Id: I30c9bc43f4b7ff9205f6a9fa6cb947b669a2fbba
(cherry picked from commit 6802f80)
When a server-group gets updated, we send an update to all hosts that
got an update - which are the hosts the instances we removed/added
belong to.

Change-Id: Ica1e516358bf6301ab7a2c59631203721dbe658d
(cherry picked from commit cfa0696)
If we don't reserve all memory, there's a swap file pre-created for
every VM on the ephemeral storage - even if it's unused.

But this option comes at the price of not being able to over-commit
memory.

Related issue: CCM-9589

Change-Id: I916f3ed8d32efc9de36b943546fee7440bbbf7ca
Note: This will later be reverted in favor of manual memory allocations.
(cherry picked from commit e028cd6)
Add global setting `bigvm_mb`

This is necessary in multiple places e.g. the scheduler and
compute-driver to handle big VMs differently. We cannot currently use
flavors for that, because there are still custom flavors in the system
that we don't control.

(cherry picked from commit 881889d)

[scheduler] Add BigVmFilter

The filter filters out hosts having more than
`bigvm_memory_utilization_max` memory utilization. This is necessary,
because it takes too long to find free space on a host for the big VM
otherwise.

(cherry picked from commit d284fc3)

[vmware] Add DRS override for "big" VMs

Since DRS doesn't play well with large differences in VM size and HANA
doesn't play well with vMotion, we're disabling automatic re-balancing
actions for "big" VMs by the DRS. On spawn, we add a
`ClusterDrsVmConfigSpec` for instances having more than by default 1 TB
of memory - configurable via `bigvm_mb`` configuration variable. The
vCenter deletes the overrides automatically when a VM is deleted.

One can view current overrides in the vCenter UI via $cluster (e.g.
productionbb098) -> Configure -> VM Overrides.

We're always adding the rule in `update_cluster_drs_vm_override`,
because we only call it in the driver's `spawn` method which seems to be
called only when a new vm object is created. Therefore, there should not
be any existing rule for the VM.

(cherry picked from commit ae68374)

[vmware] Always reserve all memory for big VMs

Since there are still custom flavors in use for big VMs, we cannot rely
on the flavors to set the reserved memory for big VMs, which is
necessary because otherwise small VMs will compete with the big VMs'
HANA, which does not work well.

We're using `CONF.bigvm_mb` here to identify a big VM and reserve all
memory regardless of `CONF.reserve_all_memory`.

(cherry picked from commit 706bcd8)

[scheduler] Make BigVmFilter more dynamic

Instead of having a static threshold for the `BigVmFilter`, we compute
the threshold depending on the hypervisor size and the requested RAM of
the big VM. The reasoning behind this is, that on bigger hypervisors a
small big VM doesn't matter as much as a big big VM, e.g. 1.4 TB on a 6
TB hypervisor vs. 5.9 TB on a 6 TB hypervisor. We basically aim at 50 %
of the requested RAM free on average over all hosts in the cluster.

The filter thus currently only works if a compute-node is in a host
aggregate defining the `_AGGREGATE_KEY` (currently "hv_size_mb") having
an integer defining the hypervisor's RAM size as a value.

(cherry picked from commit 6ad6a2c)

[scheduler] Add BigVmHypervisorRamFilter

Since we've got multiple BigVM-filters now, this also renames
`BigVmFilter` to `BigVmClusterUtilizationFilter` for clarity.

With having more diversity in the hypervisor size (e.g. 6 TB hypervisors
right around the corner), we have to make sure big VMs actually fit the
hypervisor. For that, we introduce a new scheduler filter -
`BigVmHypervisorRamFilter` - that prohibits scheduling of big VMs not
fitting the hypervisor.

In KVM-deployments, this would be the job of the `RamFilter`, but since
we run VMware and the scheduler only sees the cluster's and not a single
host's resources, we use a special host aggregate attribute -
"hv_size_mb" - to retrieve the hypervisor size as already done for
`BigVmClusterUtilizationFilter`.

(cherry picked from commit 4b6867a)

[scheduler] pep8 cleanup

(cherry picked from commit 39231e4)

Add `is_big_vm` utility function

This function should be used to check whether one is handling a big VM.
There, all necessary conditions are gathered in on place so one cannot
forget a condition. This also makes it easy to change the conditions
later on. The conditions we use to check for baremetal flavors are the
same that `nova-scheduler` uses.

(cherry picked from commit cc46cf4)

[scheduler] Remove BigVmHypervisorRamFilter

We actually don't need it, because our filter queries the placement API
for resource providers capable of fulfilling the request. With the
vmwareapi driver setting the `max_unit` value for `MEMORY_MB` to the
cluster's maximum host size, we don't have to add another filter into
the scheduler, as too small hosts won't even end up as scheduling
options.

(cherry picked from commit c2fc281)

[scheduler] Use placement API to get HV size

We recently discovered, that the hypervisor size is actually available
in the placement API. Every compute host has a resource provider with an
inventory. There, the vmwareapi virt driver sets the `max_unit` for the
`MEMORY_MB` resource class to the biggest host found in the cluster.
This means, we don't have to use aggregates to get the hypervisor size
in the BigVm filters, but can retrieve it from the placement API.

We're building a cache of the value, that expires after 10 min. This
guards the case, where a lot of VMs are scheduled in a short period of
time - even though tests showed, that querying the inventory of all
hosts in QA did not take longer than a second. Cache expiration also
guards against stale values for newly-created hypervisors that did not
set their inventory, yet.

(cherry picked from commit 965d3b4)

[vmware] Make `partiallyAutomated` a constant

We usually use variables as constants instead of directly embedding
strings.

(cherry picked from commit 81097b0)
(cherry picked from commit fbf0a2d)

Change-Id: Idca77aae46d67623f26397ba5ea0dded2892fc05
(cherry picked from commit a3db710)
[vmware] Update memoryReservationLockedToMax on resize

We need to update this setting in the case where
CONF.vmware.reserve_all_memory is False (the default) and we downsize a
big VM or upsize a normal VM to a big VM. To make it simple, we just
recompute the setting every time and set it in the reconfig spec no
matter what the previous state was.

Change-Id: Ic9283af63cb3bf90f0bed007474d7b6583866003
(cherry picked from commit 3bca302)

[vmware] Support removal of drs overrides

This commit changes `update_cluster_drs_vm_override()` to be able to
remove overrides again. This is not necessary for deletion of a VM, but
we need to remove it if a VM gets resized under the big VM limit. If
there is no override, the task will fail with `InvalidArgument`.

Change-Id: If1de5136cbc7c59babac24e8293ddb7a12ea8411
(cherry picked from commit 7ab2765)

[vmware] Remove/Add DRS overrides on resize

A VM becoming a big VM needs to get an DRS override so it doesn't move
around automatically, because that might be bad for performance.

A VM no longer being a big VM needs to get its DRS override removed,
because this interferes with spawning new VMs - especially the
special_spawning code implemented for big VMs.

We're currently unable to remove a DRS override as our SOAP library is
unable to create an appropriate request accepted by the vCenter.
Therefore, we still allow the resize to work for now and have to
manually remove the override later on.  We add code for the removal, so
we get a reminder in the logs and sentry, that this needs fixing. We
just don't fail the resize for it.

Change-Id: I89aedc29e36c86415a205b7181e06b84316bb82e
(cherry picked from commit eaad29e)
(cherry picked from commit 21b26df)

Incorporated-Change-Id: I4d344347860c7d97d6f4b2e68d9bbac069d71b74
(cherry picked from commit 860c0d5)
Some of our VMs have special spawning needs, which means they need to
spawn on their own hypervisor at first. This function helps us define
these VMs in a central place.

(cherry picked from commit e9829a7)
(cherry picked from commit 6f4ed6a)
(cherry picked from commit 14919e9)
After the recent changes of syncing server-groups,
the syncing of rules in cluster_util.update_placement has become unused.

The code can be simplified as a preparation for live-migration,
as it will add complexity.

VMops.update_cluster_placement now calls
- sync_instance_server_group, which fetches _the_ server-group
  for the instance and syncs it with the existing VMOps.sync_server_group
- update_admin_vm_group_membership handles the membership to special_spawning_vm_group
  Since that is the only remaining use-case of cluster_util.update_placement,
  the function has been renamed to update_vm_group_membership and reduced to
  that use-case

Change-Id: I94c311790610fc4658f9b06ac052ad46660f1cea
(cherry picked from commit a05999b)
(cherry picked from commit 673a3db)
joker-at-work and others added 25 commits July 2, 2026 10:54
When we log the cluster moref in getting the list of instances, we log
the whole moref and thus create multiple newlines in the log-line. To
have all data in a single line, we now only log the moref value.

Change-Id: I89d3908abdffe60570cec947e9a74b544488b535
(cherry picked from commit 920d080)
(cherry picked from commit 0c48be5)
Since we don't explicitly set a disk as boot disk and instead rely on
the order the disks have on the VirtualMachine, we need to make sure we
attach the root disk first.

Change-Id: I3ae6b5f053a3b171ed0a80215fc4204a2bf32481
(cherry picked from commit 7e6dc54)
(cherry picked from commit 2aab527)
(cherry picked from commit 1269485)
(cherry picked from commit 9e5e899)

Change-Id: Ie37a83a59ef11dda71e3f88c0fbbb2065e11c97a
(cherry picked from commit 846bcef)
If a vm has none of the requested properties,
propSet will not be set. So, we need to skip over that instance

Change-Id: Ia633fecb021bffe1557820e36c33ef53cf90db83
(cherry picked from commit 6e8f9c7)
(cherry picked from commit be82e9d)
If we disabled the host automatically, because we couldn't reach the
vCenter, we set a flag on the `VCState`. This flag is lost with a
compute-node restart, but the service stays disabled.

We now check the service's state and compare the disabled_reason on
startup to detect if we disabled the service automatically. This means,
the driver will automatically enable the service again if it can reach
the vCenter.

For the first start of a compute-node, the compute-node might not be
there. To not prohibit the creation of the compute-node, we ignore the
error raised when not finding it.
It's fine to ignore the error and not print it, because there's another
point in the code doing basically the same and printing out a message if
the compute-node doesn't exist, yet.

Change-Id: I1e49d5962adfd0bb585543c7a5580d343628f687
Incorporated-Change-Id: I25f77a69a86a876be28d31be2c626a66a5df40b3
(cherry picked from commit cc26bc3)
(cherry picked from commit fcb1363)
(cherry picked from commit c680b79)
These helper-classes allow iterating over the Task/Event objects
belonging to another object, hiding the complexity of the vSphere API
splitting those Tasks/Events into pages.

Change-Id: Ide281bdd613526561324a9368a67a720f580eb4f
Partly-Incorporated-Change-Id: I196bb9ab48867f314d9a5f3b7566384fa72778df
Incorporated-Change-Id: I86804af29f4c6aff14fa5495e5344377488ba8fe
(cherry picked from commit 368f2a7)
(cherry picked from commit 52813fa)
(cherry picked from commit c5ed5df)
(cherry picked from commit 5c0f342)
(cherry picked from commit f7bcba8)

Change-Id: Ia89d1876dfe1b6e7d872c740126b1a5fcf0470b1
Incorporated-Change-Id: I65cb4339907f5d75430c1eb44ba1fcb364b2856c
Incorporated-Change-Id: I5e4bee5f0326185a9b85f361695c941a7d813419
(cherry picked from commit d996c7b)
- Import image as VM template per datastore.
- First look on other datastores before fetching the image.

In previous versions, we also had code in here that would create a VM
from these template-VMs. We never used that feature and thus stopped
porting it forward.

When we try to fetch an image-template from another datastore, it might
happen, that the template has an incompatible hardware version and the
vcenter raises VirtualHardwareVersionNotSupported if we try to clone it
to our cluster. We handle this case by logging a debug message and
continuing with the next image-template we find, as this one is unusable
for us.

Change-Id: Ia806089b244d331003fe6f7e047b5908088ff367
Incorporated-Change-Id: If9dc9b2a13171252e5f0f0b3a99a51be2f28c6eb
Incorporated-Change-Id: I0aa58ad11c499e9423c7ecc7998325b05dd9147e
(cherry picked from commit a04c8f7)
Order of imports
Duplicate imports
Spelling mistake
Indentation

Change-Id: I4ff5594b0a628fee9579761248627099b3f251b8
(cherry picked from commit ec4bb85)
Instead of renaming `vim_util` to `vutil`, we use it directly as
`vim_util`, because we have no need to import another `vim_util`.

Change-Id: Ic484240f29573cffbbc05742da0231ce17764dca
(cherry picked from commit f5f9715)
We use the same functionality for OVA import as for normal image import,
which automatically brings handling of duplicate name.

In the process, we also fix that OVA import returned a folder path
instead of a VMDK path.

Change-Id: Iae731490716cc7592d2e99b7ca112fa56d40e4cc
(cherry picked from commit 30e15e0)
The advantage of this approach is, that we now properly
encapsulate each compute node instead of 'messing'
remotely around in another vcenter.
So caching and etc should work as expected.

The downside is additional hops:
Before: compute -> other-vcenter
Now:    compute -> messaging -> other-compute -> other-vc

So more ways of going wrong.

Change-Id: I37be358ff7c3bd9f786e6ce086e91ff2b2fc3861
(cherry picked from commit da49100)
(cherry picked from commit 7f70e86)
(e.g. when all hosts in maintainence)

(cherry picked from commit 4a32b79)
(cherry picked from commit fa208ae)
(cherry picked from commit 348fa86)
This can be used to have different CPU/memory reservations for hosts
depending on the hostgroup they're in. We can also set defaults in
percent with this instead of only static values as supported by
CONF.reserved_host_memory_mb and CONF.reserved_host_cpus.

We also have to change the `os-hypervisors/details` call to adhere to
the reservations so both Placement and Nova report the same values. It's
important to us, because we get or used to get the quota capacity from
there.

I opted for changing the resources (for that single call, hence
copy.deepcopy) instead of subtracting the reserved values from the
totals afterwards, because if an attribute is unset on the `ComputeNode`
object, we cannot access it - not even with `getattr`. It just raises a
`NotImplementedError` because it cannot fetch the attribute from
somewhere (e.g. the DB). But since we need to subtract from the total,
we would have to access the attribute. Catching the
`NotImplementedError` didn't seem like a good option to me.

With subtracting the reserved resources, we have to make sure we do not
fall below zero - which could happen for Ironic nodes, where the memory
is set to 0. With us disallowing this, one of nova's assumptions failed
- that we don't collapse negative values to 0. But since that test only
worked with reservations, it couldn't detect that we still allow
negative values. We changed the test to test if instance memory can
still reduce the free memory to below zero.

NOTE: Setting these settings too differently per hostgroup for the same
cluster might result in placement API getting confused and scheduling
being impossible, as the `max_unit` is still set to the maximum per
cluster. In case of our HANA HVs placement would therefore always
consider the HANA HVs max unit. That should be no problem as smaller VMs
should always fit.

(cherry picked from commit 5250436)
(cherry picked from commit 28f4eb8)

Change-Id: Ie4c9314bd19ec1565f3a380f74054fb1f84a0dcc
Incorporated-Change-Id: I191aedb0e3bba7698825771089cf134f320368ec
Incorporated-Change-Id: I1c92b193bf867db3a749b09bac57bde500c39e19
(cherry picked from commit 58796bc)
For this to work, the two settings `spawn_on_empty_host_vm_group` and
`spawn_somewhere_else_vm_group` need to be defined. The first one
specifies a DRS VM-group name, that should have a rule to force the VM
to spawn on the prepared host. The second setting specifies a DRS
VM-group name where all other VMs should be placed in. This group should
have a rule that prohibits all members from spawning/running on the
prepared host's hostgroup.

(cherry picked from commit 5c80f53)
(cherry picked from commit c661179)

Fix unit tests for spawn VMs on prepared empty host

This is regarding the change in _get_server_groups in inside
vm_util.py where we are checking if instance needs special
spawning.
Commit - 5c80f53

(cherry picked from commit b10324c)
(cherry picked from commit f0f7b06)

Change-Id: Iac974e16fa46399562e507c2286daa58a9e75c9d
(cherry picked from commit db05727)
With supporting memoryAllocation updates also on resize, we don't have
to lock the memory reservations to max but can use the memoryAllocation
instead. This cleans up the code, as we don't have to pass down the
parameter through a lot of functions to set
memoryReservationLockedToMax.

We still have to deconfigure `memoryReservationLockedToMax` on resize,
because there might be some old VMs still running with that setting.

Change-Id: I91d892c13b31745e190fcee8b97a2f3fb25fc014
(cherry picked from commit 02aa7dc)
(cherry picked from commit 1406e3f)
Incorporated-Change-Id: Ic9aa65ce410b42dbdee907361cb56d8b1d254fdc
(cherry picked from commit 85300f1)
VMs with reserved memory have better memory allocation
performance and -- it's suspected -- less softlock issues
too. Coincidentally, many larger VMs also have high
performance requirements that puts strict demands on the
quick availability of their memory.

Implement memory reservation and a configurable maximum
number of cluster hosts that could theoretically fail and
still let all VMs with memory reservation boot up.

Nova provides the flavor extra_spec
    "quota:memory_reservation"
which reserves the given amount of memory. This change does
not make use of that feature, but instead introduces a
parallel custom resource
    "CUSTOM_MEMORY_RESERVABLE_MB".
The reason is that "quota:memory_reservation" does not allow
for limiting the total amount of reservable memory in the
same way the resource provider mechanics do. This is a
requirement for tolerating the above-mentioned partial host
failures, which can occur because a VMware host is a cluster
of hypervisors.

Add a "vm_reservable_memory_ratio" value to the cluster
stats in the VMware driver, and use that to calculate and
return the MEMORY_RESERVABLE_MB resource from the VMware
driver's get_inventory().

The flavor-based memory reservation has less priority than the setting
`reserve_all_memory` and the reservation of all memory for big VMs.

(cherry picked from commit 93e22ef)

Change-Id: I4b1457700428189457b94739d617467248a662df
(cherry picked from commit 7f50b0b)
We already have a function listing all the VMs in a cluster
(`list_instances()`) but only returning the uuids. With this change, we
add an additional `_list_instances_in_cluster()` method called by
`list_instances()` so we do not change its interface. The method will
also return the retrieved properties of the VMs, if the
`additional_properties` parameter is set. This means we don't have to
duplicate the code.

This feature became necessary for handling the special-spawning cases of
big VMs. We don't have a mapping for VM -> host in nova and have to
retrieve it.

(cherry picked from commit 1fb23b6)
(cherry picked from commit 30daac7)

Change-Id: I02a6938c8865c18089bb03a6add80ab7ae7e37b4
(cherry picked from commit 50eb6a0)
This helper functions retrieves all DRS VM overrides of a cluster and
provides them as a dict. We plan to use this in the special_spawning
code.

Change-Id: I091878d88b8545cb094b0f534f4fa57221c33719
(cherry picked from commit 06cdb9e)
(cherry picked from commit 6f59c69)
We need to be able to spawn big VM and thus have to prepare a host for
it i.e.  free it from other VMs. This cannot be mapped in nova
currently, as nova has no view on the individual hosts in a VMware
cluster. Therefore, we implement some function in the VMware driver to
actually free up the host and also release it into the cluster again.
Placement is used for keeping a view over all clusters, as we need one
host free per HV size, per Shard, per AZ.

We have to make sure that we run the functionality only once. Placing it
into the conductor will - at least in regions with cells - run it
multiple times. So we could add some leader-election into the process or
create our own service that we only spawn once per region. We opted for
the latter, as it should be simpler.

We have a threshold in place up to which memory usage in a cluster we
try to spawn big VMs. Since trying to free a host in a too full cluster
would lead to memory overcommit on the remaining hosts, we by default
only keep or create a free host until the cluster has by default 80 %
memory usage. If a RP is marked as only accepting hana_* flavors by the
`CUSTOM_HANA_EXCLUSIVE_HOST` trait, we do not need to adhere to this
threshold. These clusters have explicit failover hosts to keep enough
resources available.

Additionally, we can also prohibit freeing up a host in a cluster or
giving back a free host to the cluster by adding the
`CUSTOM_BIGVM_DISABLED` trait to its resource provider.

Since spawning on disabled compute nodes doesn't work and Nova adds the
`COMPUTE_STATUS_DISABLED` trait to the RP, when a compute node gets
disabled, we can and should ignore those nodes when looking for a new
big VM cluster.

The placement-client has an internal cache for resource-providers, which
we need to fill to be able to use a couple of functions. Since we're
using private functions, the client doesn't call
`ensure_resource_provider()` everywhere and thus might not have the
resource-provider in the cache and thus refuses to work with it. If we
change something by a direct request to Placement's API, we also have to
update/refresh the cache.

We clean up a provider if we get an "error" returned as state. This can
happen, if the host we decided on earlier e.g. got disconnected or
became failover host. We then need to find another host - maybe in
another cluster - to be able to spawn VMs for that hypervisor size. We
also have to remove the host from the hostgroup, so it can properly join
the cluster later on. We check already freed up hosts in every run to
ensure that they are still suitable. In calling `free_host()` again, the
`nova-compute` service should return FREE_HOST_STATE_DONE if the host is
still suitable.

We also clean providers that match our naming scheme but for which we do
not find a vmware provider anymore, because they can lead to `KeyError`s
late in the code. These could be created with changing settings or
manually allowing big VMs on some cluster.

inside nova-compute
===================

If the DRS policy is not set to "fullyAutomated", i.e. if DRS will not
take action on existing, running VMs, we first check if there's already
a host free (e.g. because an operator freed one manually). If we don't
find one, we have no chance to free up a host without DRS and thus we
error out to tell nova-bigvm to search for another cluster.

We ignore failover hosts and hosts in disconnected state or maintenance
mode. This is the same as `vm_util.get_stats_from_cluster()` does for
reporting capacity cluster capacity. Reasoning: We can't spawn a VM on
any of those hosts.

These filters are not only applied when searching for a new host to
free, but also for checking on the host already destined to be freed up.
If its state changes, we return an error-state, which should let
nova-bigvm restart the search for that host's hypervisor-size.

Instead of adding up the configured memory of the VMs on a host, we
add up the used memory of the VMs. The reasoning behind this is, that it
would be faster/easier to free up the host if the VMs are not using all
their RAM, because there's less to copy around and hopefully less memory
activity.

We remove the hostgroup, because having an empty host list is not
possible. At the same time, we also have to delete the matching DRS
rule, because DRS does not update its internal state for a rule, if the
rule has become an invalid configuration. This effectively means, that
the rule stays in place if we remove the hostgroup but not the rule
using it.

Previously, we had a check in place that would return an error if no VMs
were found on the cluster. This prohibited using newly-built clusters,
that did not have a VM, so we do not want such a check anymore.

We had a case, where the vCenter discovered some random VM, which didn't
even have a `config` attribute when retrieved from the API. We now
ignore these VMs instead of letting the `KeyError` bubble up, because
they are pretty much unusable and should not matter for our
decision-making process.

Additionally, with vSphere 7 there are `vCLS` VMs providing (parts of)
the DRS service, which we need to ignore. The reason is that DRS doesn't
move those VMs, even if they violate a DRS rule. Therefore, we would
never see a host getting freed up, if it contained a `vCLS` VM. They
take up 100 MiB of reserved RAM and thus should fit next to a big VM.
Therefore, we ignore them.

With large VMs being set to partiallyAutomated, compute nodes stayed in
"waiting" state more and more often and never came out of it. Since we
still need to deploy big VMs to those compute nodes and they are usually
just stopped from being free by a large VM that cannot move, we often
mark those compute nodes free by hand. Since this doesn't scale, we want
to automate this behavior by letting the nova-compute take the same
decision.
Therefore, if there are only partiallyAutomated VMs left on a host, we
still report that host as freed up. This is done by ignoring all
`partiallyAutomated` VMs during the check of running VMs on the host.

When we spawn or resize a VM on the prepared empty host in the cluster,
we have to mark the resource as reserved on the special resource
provider. This allows the code handling the emptying of hosts to
recognize a used host and start the clean-up operations necessary after
successful spawning/resizing. Before marking the host as used, we have
to refresh the RP inventory, because the RP generation in our cache can
be out of sync.

For resizes, we have to apply it for both big->big as well as small->big
resizes.

scheduler
=========

Ignore hana/BigVM flavors by default in the ShardFilter, allowing
such flavors to be deployed on any shard.

This behaviour can be disabled globally by setting
[filter_scheduler] sharding_ignore_hana to False

It can also be disabled per project, by adding the tag
`use_individual_shard_tags_hana` to the project.

We can tell the scheduler how to determine if a flavor is hana
and/or BigVM by setting the [filter_scheduler] hana_detection_strategy
configuration to either `hana_exclusive_host` or `memory_mb`.
This has to be set to `memory_mb` for region where there are no
hana exclusive BBs and nova-bigvm is still used to free up hosts.

Co-Authored-By: Marius Leustean <marius.leustean@sap.com>
Co-Authored-By: Jakob Karge <jakob.karge@sap.com>
Change-Id: I2e6e7ecf5348ac7d32e23349c7196b65a73b4cf8
Incorporated-Change-Id: I65c2be9781b60e31d9a6c6dd84a02c7fe4aa1e72
Incorporated-Change-Id: I6e994281ae2e62096c2f5241dd493fe1f9c9d515
Incorporated-Change-Id: Idbdfe82b4057844401e710fb9d87141478bb3353
Incorporated-Change-Id: I5ceb4d9338f6d94f49cc2deff25eefb19df2030f
Incorporated-Change-Id: Ie033332436674f4fe792f4aa3f83f33b12a6d9ed
Incorporated-Change-Id: Ic9d707c59a4ea405f3a982dbe269cdfea0d03aa5
Incorporated-Change-Id: I2329db43adc00e04b07d16d312361ae5e669d298
Incorporated-Change-Id: I36813ed3d95fd8572c6b75544ebb2fc1936f6bdb
Incorporated-Change-Id: I737f312db0e156fa971a189d47efd227c666b178
Incorporated-Change-Id: I43d3d060f7c51841a8561a29d3189e37e4f87fb1
Incorporated-Change-Id: I2883c5c713ee657006c80d61ebc59a086ec22411
Incorporated-Change-Id: Ibd576211ac33f38ef0e1b9016381a955916d7c1c
Incorporated-Change-Id: I1b18a7b7db0452a10f0adc499be2df26d923f936
Incorporated-Change-Id: Ie96a41bd9151e869fabd18d69777f38db85d0ca6
Incorporated-Change-Id: Iaa1d18eb0a3e78bf1e361c8e8d1040aa07344448
Incorporated-Change-Id: Ic9b86aebbae7796fc17db3bb69f6f9ee9fffb9c9
Incorporated-Change-Id: I1eec50a5b1b6206e5b3eab8d5f9fa891fecb4b25
Incorporated-Change-Id: Ic57a71bc4e69c57833396690fc3fb5453aa122b3
Incorporated-Change-Id: Iac3b8c183f633bf5ddc59acf340b477bd1eb88cc
Incorporated-Change-Id: I47feb6a34c0e210f0ebb0edd4479550750e605d7
Incorporated-Change-Id: I22dbdcc9f135bbfc9ef05e13c801e88a78e64236
Incorporated-Change-Id: I250f203b3bb24e084ec1b499a923f7f66e638102
Incorporated-Change-Id: If3986df022273f20e109816f2752ce0254db4f10
Incorporated-Change-Id: I5a4c6c5a1894d1f6f5cff6e3475670c27bb97f28
Incorporated-Change-Id: I2905b470e91770d5951260e69a81d1910cb15972
Incorporated-Change-Id: I57cad032fc9002cb4b5013e4868215a60ebe412a
Incorporated-Change-Id: I6801fce6cf95c37096a045799d30cbde843c509a
Incorporated-Change-Id: I840e5d671c3df24cd01952b522288982ddfde80e
Incorporated-Change-Id: I71f0324395e0135d8facdbf45c74c9682093104d
Incorporated-Change-Id: I43fe1c4dc40caf5781457a0d4de83c6cb53ebc8f
Incorporated-Change-Id: Iabeae6e01f9615be7c122d1e3fd719a1e53762d9
Incorporated-Change-Id: Ieb4ad968657ef8d2bf19e08ec954da5acc51372d
Incorporated-Change-Id: I71e856382453343d8f593b330e9268d3b36b4dfa
(cherry picked from commit 21502fe)
In various places, own version of iterating over the results are implemented,
sometimes even faulty.
The following functions were only getting up to vmware.maximum_objects objects (100 by default)
vm_util.get_all_cluster_mors, vm_util.get_stats_from_cluster

Previously, the results were fetched in batches of up to vmware.maximum_objects items.
Using WithRetrieval yields an iterator to the results, which pages transparently to
the next request.
Receiver of the output of the results where changed to consume an iterator, where easily
possible.

Replace the quadratic algorithm in `ds_util._filter_datastores_matching_storage_policy`
with one of O(n log(n)) runtime

(cherry picked from commit fcabb04)

Change-Id: I2ac02a0cf4569398455dd63cfa4e2380a71b8ab9
(cherry picked from commit 84ee36d)
This extracts getting the hosts and reservations from a cluster in
get_stats_from_cluster into its own function get_hosts_and_reservations_for_cluster.

For cross-vcenter vmotion, we need to specify hosts, and we want
the same ones as we use elsewhere.

(cherry picked from commit 05cd96b)

Change-Id: I4f738e76553c3afefc735fb4b05f1a496c3c028f
(cherry picked from commit fb3d5db)
Joined the collection of the cpu-info with the host-stats in order to
avoid calling twice the property collector in different places to
get information over all the host.

Split the code into getting the data and aggregating it over the cluster.
Partly to split the logic into more easily consumable parts,
but it is also a preparation for exposing the individual ESXi hosts
as hypervisors.

Host in certain states (such as disconnected ones) do not report
`quickStats` about memory usage, so we have to assume values here, which
is better than failing updating the stats for all hosts.
Since they are not available, both the usage as well as the free memory
will not be added to the total for the cluster

Disconnected hosts also don't provide other properties, so we handle
that gracefully by defaulting them to 0.

Change-Id: I383854bb0e956519e3bdc42121b59d43ca54743d
Incorporated-Change-Id: I05b3a158a058034d9a50a6948cdf302769f2d0eb
Incorporated-Change-Id: I1c53477e891b5b95859ca267fcad8cd1bff260ef
(cherry picked from commit f6279b5)
The resource tracker iterates over all instances in
_update_usage_from_instances, where it will the fetch
for each instance the block-device-mappings in an rpc call.

By fetching the block-device-mappings up-front,
we get a single rpc/db call, instead of several small ones,
where the latencies then add up

If a block-device-mapping list cannot be retrieved for an instance,
it will fall back to the old behaviour and fetch it individually.

Change-Id: Ice9ab0a9c1b783c059687e1d992eea1f97cb3193
(cherry picked from commit 6caf72a)
(cherry picked from commit ae68565)
Clients such as the cli expect cpu_info to be a json dict,
so returning a string is breaking them.
By aggregating the individual attributes, we also work around
having different cpu models with the same flags in a cluster
not yielding any information. Now we can see that the model
mismatch, but the cpu feature flags are matching.

Change-Id: Id552121b642ec90f6e06be09825ab7339531f9d6
(cherry picked from commit a84a785)
(cherry picked from commit 273e2e7)
@leust leust requested review from fwiesel and joker-at-work July 2, 2026 07:57
@leust leust merged commit 6e45a7c into stable/2025.1-m3 Jul 2, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants