Skip to content

Commit e010a42

Browse files
Require an offering's overcommit ratio to be at least 1
The value means the same thing at every scope: how far a VM's declared size is inflated relative to what it really holds. 1 is not overcommitted at all, which is how an offering is exempted from its cluster's overcommit. Below 1 would mean the opposite, reserving more than the VM asked for. That is a different feature and nobody asked for it, but it was reachable by mistyping 1 as 0.1 - which would have charged the VM ten times its size. - rejected when the offering is created - ignored with a warning at start, for a detail written directly An offering may still declare a ratio higher than its cluster's. The value is absolute rather than relative to the cluster, so there is no contradiction in an offering being more oversubscribed than the cluster default; it is logged so it is not a surprise. Signed-off-by: Brad House <bhouse@nexthop.ai>
1 parent b8c3f08 commit e010a42

5 files changed

Lines changed: 68 additions & 21 deletions

File tree

‎PendingReleaseNotes‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,15 @@ example.ver.1 > example.ver.2:
4141
size while a stripped down Linux should fit on a 2.88MB floppy.
4242

4343
* A service offering may now set its own overcommit ratio, overriding its cluster's, using the
44-
cpuOvercommitRatio and memoryOvercommitRatio service offering details. Absent, the cluster's
45-
ratio applies as before, so nothing changes for existing offerings.
44+
cpuOvercommitRatio and memoryOvercommitRatio service offering details - the same detail keys
45+
already used at cluster and VM scope. Absent, the cluster's ratio applies as before, so nothing
46+
changes for existing offerings.
47+
48+
The value means the same thing at every scope: how far a VM's declared size is inflated
49+
relative to what it really holds. 1 means not overcommitted at all, which is how an offering is
50+
exempted from its cluster's overcommit. Values below 1 would mean reserving more than the VM
51+
asked for and are rejected. An offering may declare a ratio higher than its cluster's; this is
52+
logged.
4653

4754
An offering with a memory ratio of 1 on an overcommitted cluster is charged its full request
4855
and keeps all of it: free page reporting and balloon auto-deflate are turned off for its VMs,

‎engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java‎

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1863,8 +1863,8 @@ private void updateOverCommitRatioForVmProfile(VirtualMachineProfile vmProfile,
18631863
final float clusterCpuRatio = Float.parseFloat(clusterDetailCpu.getValue());
18641864
final float clusterRamRatio = Float.parseFloat(clusterDetailRam.getValue());
18651865

1866-
final Float offeringCpuRatio = offeringOverCommitRatio(vmProfile, VmDetailConstants.CPU_OVER_COMMIT_RATIO);
1867-
final Float offeringRamRatio = offeringOverCommitRatio(vmProfile, VmDetailConstants.MEMORY_OVER_COMMIT_RATIO);
1866+
final Float offeringCpuRatio = offeringOverCommitRatio(vmProfile, VmDetailConstants.CPU_OVER_COMMIT_RATIO, clusterCpuRatio);
1867+
final Float offeringRamRatio = offeringOverCommitRatio(vmProfile, VmDetailConstants.MEMORY_OVER_COMMIT_RATIO, clusterRamRatio);
18681868

18691869
final float cpuRatio = offeringCpuRatio != null ? offeringCpuRatio : clusterCpuRatio;
18701870
final float ramRatio = offeringRamRatio != null ? offeringRamRatio : clusterRamRatio;
@@ -1884,24 +1884,31 @@ private void updateOverCommitRatioForVmProfile(VirtualMachineProfile vmProfile,
18841884
* An offering setting a ratio of 1 on an overcommitted cluster is how infrastructure VMs are
18851885
* kept off the overcommit: they are charged their full request and hold all of it.
18861886
*/
1887-
protected Float offeringOverCommitRatio(VirtualMachineProfile vmProfile, String key) {
1887+
protected Float offeringOverCommitRatio(VirtualMachineProfile vmProfile, String key, float clusterRatio) {
18881888
String offeringRatio = _serviceOfferingDetailsDao.getDetail(vmProfile.getServiceOfferingId(), key);
18891889
if (offeringRatio == null) {
18901890
return null;
18911891
}
1892+
float ratio;
18921893
try {
1893-
float ratio = Float.parseFloat(offeringRatio);
1894-
if (ratio <= 0) {
1895-
logger.warn("Ignoring {} of {} on service offering {}: it must be greater than zero.",
1896-
key, offeringRatio, vmProfile.getServiceOfferingId());
1897-
return null;
1898-
}
1899-
return ratio;
1894+
ratio = Float.parseFloat(offeringRatio);
19001895
} catch (NumberFormatException e) {
1901-
logger.warn("Ignoring {} of {} on service offering {}: it is not a number.",
1896+
logger.warn("Ignoring {} of [{}] on service offering {}: it is not a number.",
1897+
key, offeringRatio, vmProfile.getServiceOfferingId());
1898+
return null;
1899+
}
1900+
if (ratio < 1) {
1901+
// rejected when the offering is created; only reachable by writing the detail directly
1902+
logger.warn("Ignoring {} of {} on service offering {}: it must be at least 1.",
19021903
key, offeringRatio, vmProfile.getServiceOfferingId());
19031904
return null;
19041905
}
1906+
if (ratio > clusterRatio) {
1907+
logger.info("Service offering {} declares {} of {}, more than its cluster's {}, so its VMs are "
1908+
+ "oversubscribed further than the cluster default.",
1909+
vmProfile.getServiceOfferingId(), key, ratio, clusterRatio);
1910+
}
1911+
return ratio;
19051912
}
19061913

19071914
/**

‎engine/orchestration/src/test/java/com/cloud/vm/VirtualMachineManagerOverCommitTest.java‎

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,25 +75,41 @@ private void vmDetailIs(String key, String value) {
7575
@Test
7676
public void testOfferingWithNoDetailInheritsTheCluster() {
7777
offeringSays(CPU, null);
78-
assertNull(vmManager.offeringOverCommitRatio(profile(), CPU));
78+
assertNull(vmManager.offeringOverCommitRatio(profile(), CPU, 10.0f));
7979
}
8080

8181
@Test
8282
public void testOfferingRatioIsUsed() {
8383
offeringSays(CPU, "1");
84-
assertEquals(1.0f, vmManager.offeringOverCommitRatio(profile(), CPU), 1e-6);
84+
assertEquals(1.0f, vmManager.offeringOverCommitRatio(profile(), CPU, 10.0f), 1e-6);
8585
}
8686

8787
@Test
8888
public void testNonsenseOfferingRatioInheritsTheCluster() {
8989
offeringSays(CPU, "not a number");
90-
assertNull(vmManager.offeringOverCommitRatio(profile(), CPU));
90+
assertNull(vmManager.offeringOverCommitRatio(profile(), CPU, 10.0f));
9191
}
9292

9393
@Test
9494
public void testNonPositiveOfferingRatioInheritsTheCluster() {
9595
offeringSays(CPU, "0");
96-
assertNull(vmManager.offeringOverCommitRatio(profile(), CPU));
96+
assertNull(vmManager.offeringOverCommitRatio(profile(), CPU, 10.0f));
97+
}
98+
99+
@Test
100+
public void testUndercommitIsRejected() {
101+
// below 1 would reserve more than the VM asked for. That is a different feature, and this
102+
// is how a mistyped "1" would otherwise land
103+
offeringSays(CPU, "0.1");
104+
assertNull(vmManager.offeringOverCommitRatio(profile(), CPU, 10.0f));
105+
}
106+
107+
@Test
108+
public void testAnOfferingMayBeMoreOvercommittedThanItsCluster() {
109+
// the value is absolute - "this offering is oversubscribed 20 times" - so it does not have
110+
// to sit below whatever the cluster happens to be set to
111+
offeringSays(CPU, "20");
112+
assertEquals(20.0f, vmManager.offeringOverCommitRatio(profile(), CPU, 10.0f), 1e-6);
97113
}
98114

99115
// --- what gets recorded on the VM ---

‎server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java‎

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3743,8 +3743,13 @@ public static VMLeaseManager.ExpiryAction validateAndGetLeaseExpiryAction(Intege
37433743
}
37443744

37453745
/**
3746-
* A service offering may set its own overcommit ratio to override its cluster's, most usefully
3747-
* a ratio of 1 to keep infrastructure VMs off an overcommitted cluster's overcommit.
3746+
* A service offering may declare its own overcommit ratio, overriding whatever its cluster is
3747+
* set to. The value means the same thing at every scope: how far the declared size is inflated
3748+
* relative to what the VM really holds. 1 is not overcommitted at all, which is how a VM is
3749+
* exempted from a cluster's overcommit.
3750+
*
3751+
* Below 1 would mean the opposite - reserving more than the VM asked for. That is a different
3752+
* feature and is rejected rather than being reachable by mistyping 1 as 0.1.
37483753
*/
37493754
protected void validateOverCommitRatioInServiceOfferingDetail(String key, String value) {
37503755
float ratio;
@@ -3753,8 +3758,10 @@ protected void validateOverCommitRatioInServiceOfferingDetail(String key, String
37533758
} catch (NumberFormatException | NullPointerException e) {
37543759
throw new InvalidParameterValueException(String.format("Service offering detail %s must be a number, got [%s].", key, value));
37553760
}
3756-
if (ratio <= 0) {
3757-
throw new InvalidParameterValueException(String.format("Service offering detail %s must be greater than zero, got [%s].", key, value));
3761+
if (ratio < 1) {
3762+
throw new InvalidParameterValueException(String.format(
3763+
"Service offering detail %s must be at least 1, got [%s]. 1 means the offering is not "
3764+
+ "overcommitted; higher values mean it is oversubscribed by that factor.", key, value));
37583765
}
37593766
}
37603767

‎server/src/test/java/com/cloud/configuration/ConfigurationManagerOverCommitDetailTest.java‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@ public void testRatiosAreAccepted() {
3838
validate("10.5");
3939
}
4040

41+
@Test(expected = InvalidParameterValueException.class)
42+
public void testUndercommitIsRejected() {
43+
validate("0.1");
44+
}
45+
46+
@Test(expected = InvalidParameterValueException.class)
47+
public void testJustBelowOneIsRejected() {
48+
validate("0.99");
49+
}
50+
4151
@Test(expected = InvalidParameterValueException.class)
4252
public void testZeroIsRejected() {
4353
validate("0");

0 commit comments

Comments
 (0)