Skip to content

Commit

Permalink
Properly calculate a cluster's free memory
Browse files Browse the repository at this point in the history
cluster free memory in the vSphere CPI uses "effective_memory" [0]
defined as follows [1]:

  Effective memory resources (in MB) available to run virtual
  machines. This is the aggregated effective resource level from all
  running hosts. Hosts that are in maintenance mode or are unresponsive
  are not counted. Resources used by the VMware Service Console are not
  included in the aggregate. This value represents the amount of resources
  available for the root resource pool for running virtual machines.

This sounds like it's "available free memory", but it's not. It's total
effective memory that a cluster could give to VMs. This is the wrong
metric to use for "free memory" as it does not vary based on the memory
consumption for the cluster.

This commit changes the calculation to subtract from the effective
memory the memory demand, "Sum of memory demand of all the powered-on
VMs in the cluster" [2].

The new metric appears to more closely reflect vCenter's reporting of
memory. For example, on https://vcenter-80.nono.io: the effective memory

   490 GiB   effective memory, old, wrong calculation
  - 86 GiB   demand memory
   -------
   404 GiB   new, better calculation

   420 GiB   vCenter's reporting of "Available Reservation"

Note that although this new calculation of memory is more "truthful",
measuring memory is nuanced: vSphere has 3 different metrics for memory
use (memDemandMB, memEntitledMB, memReservationMB). Furthermore, on
vCenter's cluster's summary page, the "free" memory (e.g. 184 GiB)
doesn't dovetail with _any_ of the available metrics, nor any
combination thereof.

Drive-by:

- I changed `VimSdk::Vim::ComputeResource::Summary` →
  `VimSdk::Vim::ClusterComputeResource::Summary` in our tests because
  that was the object reflected in the vSphere MOB browser (we were
  instance-doubling the wrong object).

[0] https://github.com/cloudfoundry/bosh-vsphere-cpi-release/blob/3fc6d72d7c69b40416e78663238a15d022a98415/src/vsphere_cpi/lib/cloud/vsphere/resources/cluster.rb#L209-L216

[1] https://vdc-download.vmware.com/vmwb-repository/dcr-public/90ec343b-df7c-493e-9979-36ea55765102/8753fd1e-fcab-4bd4-9cde-a364851f31a6/vim.cluster.UsageSummary.html

[2] https://vdc-download.vmware.com/vmwb-repository/dcr-public/3d076a12-29a2-4d17-9269-cb8150b5a37f/8b5969e2-1a66-4425-af17-feff6d6f705d/SDK/sms-sdk/docs/ReferenceGuide/vim.ComputeResource.Summary.html#effectiveMemory

[#183481442]
  • Loading branch information
cunnie committed Oct 27, 2023
1 parent 9f6166f commit b5d77ca
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 5 deletions.
2 changes: 1 addition & 1 deletion src/vsphere_cpi/lib/cloud/vsphere/resources/cluster.rb
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ def fetch_cluster_utilization()
raise "Failed to get utilization for cluster'#{self.mob.name}'" if properties.nil?

compute_resource_summary = properties["summary"]
return compute_resource_summary.effective_memory
return compute_resource_summary.effective_memory - compute_resource_summary.usage_summary.mem_demand_mb
end

# Fetches the resource pool utilization from vSphere.
Expand Down
15 changes: 11 additions & 4 deletions src/vsphere_cpi/spec/unit/cloud/vsphere/resources/cluster_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ def generate_host_property(mob:, name:, connection_state:, maintenance_mode:, me
let(:active_host_1_mob) { instance_double('VimSdk::Vim::ClusterComputeResource') }
let(:active_host_2_mob) { instance_double('VimSdk::Vim::ClusterComputeResource') }
let(:active_host_mobs) { [active_host_1_mob, active_host_2_mob] }
let(:compute_summary) { instance_double('VimSdk::Vim::ComputeResource::Summary') }
let(:compute_summary) { instance_double('VimSdk::Vim::ClusterComputeResource::Summary') }
let(:cluster_usage_summary) { instance_double('VimSdk::Vim::Cluster::UsageSummary') }
let(:active_hosts_properties) do
{}.merge(
generate_host_property(mob: active_host_1_mob, name: 'mob-1', maintenance_mode: false, memory_size: 100 * 1024 * 1024, power_state: 'poweredOn', connection_state: 'connected')
Expand All @@ -183,7 +184,9 @@ def generate_host_property(mob:, name:, connection_state:, maintenance_mode:, me

before do
allow(cloud_searcher).to receive(:get_properties).and_return({"summary" => compute_summary})
allow(compute_summary).to receive(:effective_memory).and_return(85)
allow(compute_summary).to receive(:effective_memory).and_return(90)
allow(compute_summary).to receive(:usage_summary).and_return(cluster_usage_summary)
allow(cluster_usage_summary).to receive(:mem_demand_mb).and_return(5)
end

it 'sets resources to values based on the active hosts in the cluster' do
Expand Down Expand Up @@ -244,6 +247,7 @@ def generate_host_property(mob:, name:, connection_state:, maintenance_mode:, me
end
before do
allow(compute_summary).to receive(:effective_memory).and_return(0)
allow(cluster_usage_summary).to receive(:mem_demand_mb).and_return(0)
end
it 'defaults free memory to zero' do
expect(cluster.free_memory.cluster_free_memory_mb).to eq(0)
Expand Down Expand Up @@ -291,12 +295,15 @@ def generate_host_property(mob:, name:, connection_state:, maintenance_mode:, me
end

context 'when host group rule type is SHOULD' do
let(:compute_summary) { instance_double('VimSdk::Vim::ComputeResource::Summary') }
let(:compute_summary) { instance_double('VimSdk::Vim::ClusterComputeResource::Summary') }
let(:cluster_usage_summary) { instance_double('VimSdk::Vim::Cluster::UsageSummary') }

before do
allow(subject).to receive(:host_group_rule_type).and_return('SHOULD')
allow(cloud_searcher).to receive(:get_properties).and_return({"summary" => compute_summary})
allow(compute_summary).to receive(:effective_memory).and_return(85)
allow(compute_summary).to receive(:usage_summary).and_return(cluster_usage_summary)
allow(compute_summary).to receive(:effective_memory).and_return(90)
allow(cluster_usage_summary).to receive(:mem_demand_mb).and_return(5)
end

it 'returns full cluster free memory in Megabytes for cluster free memory' do
Expand Down

0 comments on commit b5d77ca

Please sign in to comment.