Skip to content

Commit ce78525

Browse files
Merge branch '4.20' into polish_server
2 parents e0fa2f4 + 47a6ac8 commit ce78525

File tree

41 files changed

+3802
-721
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+3802
-721
lines changed

agent/src/main/java/com/cloud/agent/Agent.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1228,7 +1228,14 @@ public void doTask(final Task task) throws TaskExecutionException {
12281228
logger.error("Error parsing task", e);
12291229
}
12301230
} else if (task.getType() == Task.Type.DISCONNECT) {
1231-
logger.debug("Executing disconnect task - {}", () -> getLinkLog(task.getLink()));
1231+
try {
1232+
// an issue has been found if reconnect immediately after disconnecting.
1233+
// wait 5 seconds before reconnecting
1234+
logger.debug("Wait for 5 secs before reconnecting, disconnect task - {}", () -> getLinkLog(task.getLink()));
1235+
Thread.sleep(5000);
1236+
} catch (InterruptedException e) {
1237+
}
1238+
logger.debug("Executing disconnect task - {} and reconnecting", () -> getLinkLog(task.getLink()));
12321239
reconnect(task.getLink());
12331240
} else if (task.getType() == Task.Type.OTHER) {
12341241
processOtherTask(task);

api/src/main/java/com/cloud/server/ManagementService.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@
7171
import com.cloud.capacity.Capacity;
7272
import com.cloud.dc.Pod;
7373
import com.cloud.dc.Vlan;
74+
import com.cloud.deploy.DeploymentPlan;
75+
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
7476
import com.cloud.exception.ConcurrentOperationException;
7577
import com.cloud.exception.ManagementServerException;
7678
import com.cloud.exception.ResourceUnavailableException;
@@ -91,6 +93,7 @@
9193
import com.cloud.vm.InstanceGroup;
9294
import com.cloud.vm.VirtualMachine;
9395
import com.cloud.vm.VirtualMachine.Type;
96+
import com.cloud.vm.VirtualMachineProfile;
9497

9598
/**
9699
* Hopefully this is temporary.
@@ -452,6 +455,19 @@ public interface ManagementService {
452455

453456
Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>> listHostsForMigrationOfVM(VirtualMachine vm, Long startIndex, Long pageSize, String keyword, List<VirtualMachine> vmList);
454457

458+
/**
459+
* Apply affinity group constraints and other exclusion rules for VM migration.
460+
* This is a helper method that can be used independently for per-iteration affinity checks in DRS.
461+
*
462+
* @param vm The virtual machine to migrate
463+
* @param vmProfile The VM profile
464+
* @param plan The deployment plan
465+
* @param vmList List of VMs with current/simulated placements for affinity processing
466+
* @return ExcludeList containing hosts to avoid
467+
*/
468+
ExcludeList applyAffinityConstraints(VirtualMachine vm, VirtualMachineProfile vmProfile,
469+
DeploymentPlan plan, List<VirtualMachine> vmList);
470+
455471
/**
456472
* List storage pools for live migrating of a volume. The API returns list of all pools in the cluster to which the
457473
* volume can be migrated. Current pool is not included in the list. In case of vSphere datastore cluster storage pools,

api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateManagementNetworkIpRangeCmd.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import com.cloud.exception.ResourceAllocationException;
3535
import com.cloud.exception.ResourceUnavailableException;
3636
import com.cloud.user.Account;
37+
import com.cloud.utils.StringUtils;
3738

3839
@APICommand(name = "createManagementNetworkIpRange",
3940
description = "Creates a Management network IP range.",
@@ -118,7 +119,7 @@ public Boolean isForSystemVms() {
118119
}
119120

120121
public String getVlan() {
121-
if (vlan == null || vlan.isEmpty()) {
122+
if (StringUtils.isBlank(vlan)) {
122123
vlan = "untagged";
123124
}
124125
return vlan;

api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.apache.cloudstack.api.command.admin.vlan;
1818

1919
import com.cloud.utils.net.NetUtils;
20+
import com.cloud.utils.StringUtils;
2021

2122
import org.apache.cloudstack.api.APICommand;
2223
import org.apache.cloudstack.api.ApiConstants;
@@ -162,7 +163,7 @@ public boolean isForNsx() {
162163
}
163164

164165
public String getVlan() {
165-
if ((vlan == null || vlan.isEmpty()) && !isForNsx()) {
166+
if (StringUtils.isBlank(vlan) && !isForNsx()) {
166167
vlan = "untagged";
167168
}
168169
return vlan;

api/src/main/java/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ public String getUrl() {
211211
}
212212

213213
public String getTemplateTag() {
214-
return templateTag;
214+
return StringUtils.isBlank(templateTag) ? null : templateTag;
215215
}
216216

217217
public Map getDetails() {

api/src/main/java/org/apache/cloudstack/api/command/user/template/GetUploadParamsForTemplateCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ public Boolean isSshKeyEnabled() {
160160
}
161161

162162
public String getTemplateTag() {
163-
return templateTag;
163+
return StringUtils.isBlank(templateTag) ? null : templateTag;
164164
}
165165

166166
public boolean isDeployAsIs() {

api/src/main/java/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ public String getChecksum() {
265265
}
266266

267267
public String getTemplateTag() {
268-
return templateTag;
268+
return StringUtils.isBlank(templateTag) ? null : templateTag;
269269
}
270270

271271
public Map getDetails() {

api/src/main/java/org/apache/cloudstack/cluster/ClusterDrsAlgorithm.java

Lines changed: 115 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@
2222
import com.cloud.host.Host;
2323
import com.cloud.offering.ServiceOffering;
2424
import com.cloud.org.Cluster;
25-
import com.cloud.utils.Pair;
2625
import com.cloud.utils.Ternary;
2726
import com.cloud.utils.component.Adapter;
2827
import com.cloud.vm.VirtualMachine;
28+
import org.apache.commons.collections.CollectionUtils;
2929
import org.apache.commons.math3.stat.descriptive.moment.Mean;
3030
import org.apache.commons.math3.stat.descriptive.moment.StandardDeviation;
3131

@@ -40,6 +40,9 @@
4040

4141
public interface ClusterDrsAlgorithm extends Adapter {
4242

43+
Mean MEAN_CALCULATOR = new Mean();
44+
StandardDeviation STDDEV_CALCULATOR = new StandardDeviation(false);
45+
4346
/**
4447
* Determines whether a DRS operation is needed for a given cluster and host-VM
4548
* mapping.
@@ -59,79 +62,121 @@ public interface ClusterDrsAlgorithm extends Adapter {
5962
boolean needsDrs(Cluster cluster, List<Ternary<Long, Long, Long>> cpuList,
6063
List<Ternary<Long, Long, Long>> memoryList) throws ConfigurationException;
6164

62-
6365
/**
64-
* Determines the metrics for a given virtual machine and destination host in a DRS cluster.
65-
*
66-
* @param clusterId
67-
* the ID of the cluster to check
68-
* @param vm
69-
* the virtual machine to check
70-
* @param serviceOffering
71-
* the service offering for the virtual machine
72-
* @param destHost
73-
* the destination host for the virtual machine
74-
* @param hostCpuMap
75-
* a map of host IDs to the Ternary of used, reserved and total CPU on each host
76-
* @param hostMemoryMap
77-
* a map of host IDs to the Ternary of used, reserved and total memory on each host
78-
* @param requiresStorageMotion
79-
* whether storage motion is required for the virtual machine
66+
* Calculates the metrics (improvement, cost, benefit) for migrating a VM to a destination host. Improvement is
67+
* calculated based on the change in cluster imbalance before and after the migration.
8068
*
69+
* @param cluster the cluster to check
70+
* @param vm the virtual machine to check
71+
* @param serviceOffering the service offering for the virtual machine
72+
* @param destHost the destination host for the virtual machine
73+
* @param hostCpuMap a map of host IDs to the Ternary of used, reserved and total CPU on each host
74+
* @param hostMemoryMap a map of host IDs to the Ternary of used, reserved and total memory on each host
75+
* @param requiresStorageMotion whether storage motion is required for the virtual machine
76+
* @param preImbalance the pre-calculated cluster imbalance before migration (null to calculate it)
77+
* @param baseMetricsArray pre-calculated array of all host metrics before migration
78+
* @param hostIdToIndexMap mapping from host ID to index in the metrics array
8179
* @return a ternary containing improvement, cost, benefit
8280
*/
8381
Ternary<Double, Double, Double> getMetrics(Cluster cluster, VirtualMachine vm, ServiceOffering serviceOffering,
8482
Host destHost, Map<Long, Ternary<Long, Long, Long>> hostCpuMap,
8583
Map<Long, Ternary<Long, Long, Long>> hostMemoryMap,
86-
Boolean requiresStorageMotion) throws ConfigurationException;
84+
Boolean requiresStorageMotion, Double preImbalance,
85+
double[] baseMetricsArray, Map<Long, Integer> hostIdToIndexMap) throws ConfigurationException;
8786

8887
/**
89-
* Calculates the imbalance of the cluster after a virtual machine migration.
88+
* Calculates the cluster imbalance after migrating a VM to a destination host.
9089
*
91-
* @param serviceOffering
92-
* the service offering for the virtual machine
93-
* @param vm
94-
* the virtual machine being migrated
95-
* @param destHost
96-
* the destination host for the virtual machine
97-
* @param hostCpuMap
98-
* a map of host IDs to the Ternary of used, reserved and total CPU on each host
99-
* @param hostMemoryMap
100-
* a map of host IDs to the Ternary of used, reserved and total memory on each host
90+
* @param vm the virtual machine being migrated
91+
* @param destHost the destination host for the virtual machine
92+
* @param clusterId the cluster ID
93+
* @param vmMetric the VM's resource consumption metric
94+
* @param baseMetricsArray pre-calculated array of all host metrics before migration
95+
* @param hostIdToIndexMap mapping from host ID to index in the metrics array
96+
* @return the cluster imbalance after migration
97+
*/
98+
default Double getImbalancePostMigration(VirtualMachine vm,
99+
Host destHost, Long clusterId, long vmMetric, double[] baseMetricsArray,
100+
Map<Long, Integer> hostIdToIndexMap, Map<Long, Ternary<Long, Long, Long>> hostCpuMap,
101+
Map<Long, Ternary<Long, Long, Long>> hostMemoryMap) {
102+
// Create a copy of the base array and adjust only the two affected hosts
103+
double[] adjustedMetrics = new double[baseMetricsArray.length];
104+
System.arraycopy(baseMetricsArray, 0, adjustedMetrics, 0, baseMetricsArray.length);
105+
106+
long destHostId = destHost.getId();
107+
long vmHostId = vm.getHostId();
108+
109+
// Adjust source host (remove VM resources)
110+
Integer sourceIndex = hostIdToIndexMap.get(vmHostId);
111+
if (sourceIndex != null && sourceIndex < adjustedMetrics.length) {
112+
Map<Long, Ternary<Long, Long, Long>> sourceMetricsMap = getClusterDrsMetric(clusterId).equals("cpu") ? hostCpuMap : hostMemoryMap;
113+
Ternary<Long, Long, Long> sourceMetrics = sourceMetricsMap.get(vmHostId);
114+
if (sourceMetrics != null) {
115+
adjustedMetrics[sourceIndex] = getMetricValuePostMigration(clusterId, sourceMetrics, vmMetric, vmHostId, destHostId, vmHostId);
116+
}
117+
}
118+
119+
// Adjust destination host (add VM resources)
120+
Integer destIndex = hostIdToIndexMap.get(destHostId);
121+
if (destIndex != null && destIndex < adjustedMetrics.length) {
122+
Map<Long, Ternary<Long, Long, Long>> destMetricsMap = getClusterDrsMetric(clusterId).equals("cpu") ? hostCpuMap : hostMemoryMap;
123+
Ternary<Long, Long, Long> destMetrics = destMetricsMap.get(destHostId);
124+
if (destMetrics != null) {
125+
adjustedMetrics[destIndex] = getMetricValuePostMigration(clusterId, destMetrics, vmMetric, destHostId, destHostId, vmHostId);
126+
}
127+
}
128+
129+
return calculateImbalance(adjustedMetrics);
130+
}
131+
132+
/**
133+
* Calculate imbalance from an array of metric values.
134+
* Imbalance is defined as standard deviation divided by mean.
101135
*
102-
* @return a pair containing the CPU and memory imbalance of the cluster after the migration
136+
* Uses reusable stateless calculator objects to avoid object creation overhead.
137+
* @param values array of metric values
138+
* @return calculated imbalance
103139
*/
104-
default Double getImbalancePostMigration(ServiceOffering serviceOffering, VirtualMachine vm,
105-
Host destHost, Map<Long, Ternary<Long, Long, Long>> hostCpuMap,
106-
Map<Long, Ternary<Long, Long, Long>> hostMemoryMap) throws ConfigurationException {
107-
Pair<Long, Map<Long, Ternary<Long, Long, Long>>> pair = getHostMetricsMapAndType(destHost.getClusterId(), serviceOffering, hostCpuMap, hostMemoryMap);
108-
long vmMetric = pair.first();
109-
Map<Long, Ternary<Long, Long, Long>> hostMetricsMap = pair.second();
140+
private static double calculateImbalance(double[] values) {
141+
if (values == null || values.length == 0) {
142+
return 0.0;
143+
}
110144

111-
List<Double> list = new ArrayList<>();
112-
for (Long hostId : hostMetricsMap.keySet()) {
113-
list.add(getMetricValuePostMigration(destHost.getClusterId(), hostMetricsMap.get(hostId), vmMetric, hostId, destHost.getId(), vm.getHostId()));
145+
double mean = MEAN_CALCULATOR.evaluate(values);
146+
if (mean == 0.0) {
147+
return 0.0; // Avoid division by zero
114148
}
115-
return getImbalance(list);
149+
double stdDev = STDDEV_CALCULATOR.evaluate(values, mean);
150+
return stdDev / mean;
116151
}
117152

118-
private Pair<Long, Map<Long, Ternary<Long, Long, Long>>> getHostMetricsMapAndType(Long clusterId,
119-
ServiceOffering serviceOffering, Map<Long, Ternary<Long, Long, Long>> hostCpuMap,
120-
Map<Long, Ternary<Long, Long, Long>> hostMemoryMap) throws ConfigurationException {
153+
/**
154+
* Helper method to get VM metric based on cluster configuration.
155+
*/
156+
static long getVmMetric(ServiceOffering serviceOffering, Long clusterId) throws ConfigurationException {
121157
String metric = getClusterDrsMetric(clusterId);
122-
Pair<Long, Map<Long, Ternary<Long, Long, Long>>> pair;
123158
switch (metric) {
124159
case "cpu":
125-
pair = new Pair<>((long) serviceOffering.getCpu() * serviceOffering.getSpeed(), hostCpuMap);
126-
break;
160+
return (long) serviceOffering.getCpu() * serviceOffering.getSpeed();
127161
case "memory":
128-
pair = new Pair<>(serviceOffering.getRamSize() * 1024L * 1024L, hostMemoryMap);
129-
break;
162+
return serviceOffering.getRamSize() * 1024L * 1024L;
130163
default:
131164
throw new ConfigurationException(
132165
String.format("Invalid metric: %s for cluster: %d", metric, clusterId));
133166
}
134-
return pair;
167+
}
168+
169+
/**
170+
* Helper method to calculate metrics from pre and post imbalance values.
171+
*/
172+
default Ternary<Double, Double, Double> calculateMetricsFromImbalances(Double preImbalance, Double postImbalance) {
173+
// This needs more research to determine the cost and benefit of a migration
174+
// TODO: Cost should be a factor of the VM size and the host capacity
175+
// TODO: Benefit should be a factor of the VM size and the host capacity and the number of VMs on the host
176+
final double improvement = preImbalance - postImbalance;
177+
final double cost = 0.0;
178+
final double benefit = 1.0;
179+
return new Ternary<>(improvement, cost, benefit);
135180
}
136181

137182
private Double getMetricValuePostMigration(Long clusterId, Ternary<Long, Long, Long> metrics, long vmMetric,
@@ -151,9 +196,26 @@ private Double getMetricValuePostMigration(Long clusterId, Ternary<Long, Long, L
151196
}
152197

153198
private static Double getImbalance(List<Double> metricList) {
154-
Double clusterMeanMetric = getClusterMeanMetric(metricList);
155-
Double clusterStandardDeviation = getClusterStandardDeviation(metricList, clusterMeanMetric);
156-
return clusterStandardDeviation / clusterMeanMetric;
199+
if (CollectionUtils.isEmpty(metricList)) {
200+
return 0.0;
201+
}
202+
// Convert List<Double> to double[] once, avoiding repeated conversions
203+
double[] values = new double[metricList.size()];
204+
int index = 0;
205+
for (Double value : metricList) {
206+
if (value != null) {
207+
values[index++] = value;
208+
}
209+
}
210+
211+
// Trim array if some values were null
212+
if (index < values.length) {
213+
double[] trimmed = new double[index];
214+
System.arraycopy(values, 0, trimmed, 0, index);
215+
values = trimmed;
216+
}
217+
218+
return calculateImbalance(values);
157219
}
158220

159221
static String getClusterDrsMetric(long clusterId) {
@@ -181,36 +243,6 @@ static Double getMetricValue(long clusterId, long used, long free, long total, F
181243
return null;
182244
}
183245

184-
/**
185-
* Mean is the average of a collection or set of metrics. In context of a DRS
186-
* cluster, the cluster metrics defined as the average metrics value for some
187-
* metric (such as CPU, memory etc.) for every resource such as host.
188-
* Cluster Mean Metric, mavg = (∑mi) / N, where mi is a measurable metric for a
189-
* resource ‘i’ in a cluster with total N number of resources.
190-
*/
191-
static Double getClusterMeanMetric(List<Double> metricList) {
192-
return new Mean().evaluate(metricList.stream().mapToDouble(i -> i).toArray());
193-
}
194-
195-
/**
196-
* Standard deviation is defined as the square root of the absolute squared sum
197-
* of difference of a metric from its mean for every resource divided by the
198-
* total number of resources. In context of the DRS, the cluster standard
199-
* deviation is the standard deviation based on a metric of resources in a
200-
* cluster such as for the allocation or utilisation CPU/memory metric of hosts
201-
* in a cluster.
202-
* Cluster Standard Deviation, σc = sqrt((∑∣mi−mavg∣^2) / N), where mavg is the
203-
* mean metric value and mi is a measurable metric for some resource ‘i’ in the
204-
* cluster with total N number of resources.
205-
*/
206-
static Double getClusterStandardDeviation(List<Double> metricList, Double mean) {
207-
if (mean != null) {
208-
return new StandardDeviation(false).evaluate(metricList.stream().mapToDouble(i -> i).toArray(), mean);
209-
} else {
210-
return new StandardDeviation(false).evaluate(metricList.stream().mapToDouble(i -> i).toArray());
211-
}
212-
}
213-
214246
static boolean getDrsMetricUseRatio(long clusterId) {
215247
return ClusterDrsMetricUseRatio.valueIn(clusterId);
216248
}

debian/rules

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ VERSION := $(shell grep '<version>' pom.xml | head -2 | tail -1 | cut -d'>' -f2
44
PACKAGE = $(shell dh_listpackages|head -n 1|cut -d '-' -f 1)
55
SYSCONFDIR = "/etc"
66
DESTDIR = "debian/tmp"
7-
CMK_REL := $(shell wget -O - "https://api.github.com/repos/apache/cloudstack-cloudmonkey/releases" 2>/dev/null | jq -r '.[0].tag_name')
87

98
%:
109
dh $@ --with systemd
@@ -86,7 +85,7 @@ override_dh_auto_install:
8685
rm -rf $(DESTDIR)/usr/share/$(PACKAGE)-management/templates/systemvm/md5sum.txt
8786

8887
# Bundle cmk in cloudstack-management
89-
wget https://github.com/apache/cloudstack-cloudmonkey/releases/download/$(CMK_REL)/cmk.linux.x86-64 -O $(DESTDIR)/usr/bin/cmk
88+
wget https://github.com/apache/cloudstack-cloudmonkey/releases/latest/download/cmk.linux.x86-64 -O $(DESTDIR)/usr/bin/cmk
9089
chmod +x $(DESTDIR)/usr/bin/cmk
9190

9291
# nast hack for a couple of configuration files

0 commit comments

Comments
 (0)