Skip to content

Commit 6ad1739

Browse files
author
Daan Hoogland
committed
Merge branch '4.19' into 4.20
2 parents ed6ee6b + a4263da commit 6ad1739

File tree

24 files changed

+426
-514
lines changed

24 files changed

+426
-514
lines changed

api/src/main/java/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ public void execute() {
7272
response.setInstancesDisksStatsRetentionTime((Integer) capabilities.get(ApiConstants.INSTANCES_DISKS_STATS_RETENTION_TIME));
7373
response.setSharedFsVmMinCpuCount((Integer)capabilities.get(ApiConstants.SHAREDFSVM_MIN_CPU_COUNT));
7474
response.setSharedFsVmMinRamSize((Integer)capabilities.get(ApiConstants.SHAREDFSVM_MIN_RAM_SIZE));
75+
response.setDynamicScalingEnabled((Boolean) capabilities.get(ApiConstants.DYNAMIC_SCALING_ENABLED));
7576
response.setObjectName("capability");
7677
response.setResponseName(getCommandName());
7778
this.setResponseObject(response);

api/src/main/java/org/apache/cloudstack/api/response/CapabilitiesResponse.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ public class CapabilitiesResponse extends BaseResponse {
136136
@Param(description = "the min Ram size for the service offering used by the shared filesystem instance", since = "4.20.0")
137137
private Integer sharedFsVmMinRamSize;
138138

139+
@SerializedName(ApiConstants.DYNAMIC_SCALING_ENABLED)
140+
@Param(description = "true if dynamically scaling for instances is enabled", since = "4.21.0")
141+
private Boolean dynamicScalingEnabled;
142+
139143
public void setSecurityGroupsEnabled(boolean securityGroupsEnabled) {
140144
this.securityGroupsEnabled = securityGroupsEnabled;
141145
}
@@ -247,4 +251,8 @@ public void setSharedFsVmMinCpuCount(Integer sharedFsVmMinCpuCount) {
247251
public void setSharedFsVmMinRamSize(Integer sharedFsVmMinRamSize) {
248252
this.sharedFsVmMinRamSize = sharedFsVmMinRamSize;
249253
}
254+
255+
public void setDynamicScalingEnabled(Boolean dynamicScalingEnabled) {
256+
this.dynamicScalingEnabled = dynamicScalingEnabled;
257+
}
250258
}

core/src/main/java/com/cloud/agent/api/CheckVolumeAnswer.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,33 @@
1717

1818
package com.cloud.agent.api;
1919

20+
import org.apache.cloudstack.storage.volume.VolumeOnStorageTO;
21+
22+
import java.util.Map;
23+
2024
public class CheckVolumeAnswer extends Answer {
2125

2226
private long size;
27+
private Map<VolumeOnStorageTO.Detail, String> volumeDetails;
2328

2429
CheckVolumeAnswer() {
2530
}
2631

27-
public CheckVolumeAnswer(CheckVolumeCommand cmd, String details, long size) {
28-
super(cmd, true, details);
32+
public CheckVolumeAnswer(CheckVolumeCommand cmd, final boolean success, String details, long size,
33+
Map<VolumeOnStorageTO.Detail, String> volumeDetails) {
34+
super(cmd, success, details);
2935
this.size = size;
36+
this.volumeDetails = volumeDetails;
3037
}
3138

3239
public long getSize() {
3340
return size;
3441
}
3542

43+
public Map<VolumeOnStorageTO.Detail, String> getVolumeDetails() {
44+
return volumeDetails;
45+
}
46+
3647
public String getString() {
3748
return "CheckVolumeAnswer [size=" + size + "]";
3849
}

core/src/main/java/com/cloud/agent/api/CopyRemoteVolumeAnswer.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,28 @@
1717

1818
package com.cloud.agent.api;
1919

20+
import org.apache.cloudstack.storage.volume.VolumeOnStorageTO;
21+
22+
import java.util.Map;
23+
2024
public class CopyRemoteVolumeAnswer extends Answer {
2125

2226
private String remoteIp;
2327
private String filename;
2428

2529
private long size;
30+
private Map<VolumeOnStorageTO.Detail, String> volumeDetails;
2631

2732
CopyRemoteVolumeAnswer() {
2833
}
2934

30-
public CopyRemoteVolumeAnswer(CopyRemoteVolumeCommand cmd, String details, String filename, long size) {
31-
super(cmd, true, details);
35+
public CopyRemoteVolumeAnswer(CopyRemoteVolumeCommand cmd, final boolean success, String details, String filename, long size,
36+
Map<VolumeOnStorageTO.Detail, String> volumeDetails) {
37+
super(cmd, success, details);
3238
this.remoteIp = cmd.getRemoteIp();
3339
this.filename = filename;
3440
this.size = size;
41+
this.volumeDetails = volumeDetails;
3542
}
3643

3744
public String getRemoteIp() {
@@ -54,6 +61,10 @@ public long getSize() {
5461
return size;
5562
}
5663

64+
public Map<VolumeOnStorageTO.Detail, String> getVolumeDetails() {
65+
return volumeDetails;
66+
}
67+
5768
public String getString() {
5869
return "CopyRemoteVolumeAnswer [remoteIp=" + remoteIp + "]";
5970
}

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckVolumeCommandWrapper.java

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,24 @@
3131
import com.cloud.resource.ResourceWrapper;
3232
import com.cloud.storage.Storage;
3333
import com.cloud.utils.exception.CloudRuntimeException;
34+
import org.apache.cloudstack.storage.volume.VolumeOnStorageTO;
3435
import org.apache.cloudstack.utils.qemu.QemuImg;
3536
import org.apache.cloudstack.utils.qemu.QemuImgException;
3637
import org.apache.cloudstack.utils.qemu.QemuImgFile;
38+
import org.apache.commons.collections.MapUtils;
39+
import org.apache.commons.lang3.StringUtils;
3740
import org.libvirt.LibvirtException;
3841

42+
import java.util.Arrays;
43+
import java.util.HashMap;
44+
import java.util.List;
3945
import java.util.Map;
4046

4147
@ResourceWrapper(handles = CheckVolumeCommand.class)
4248
public final class LibvirtCheckVolumeCommandWrapper extends CommandWrapper<CheckVolumeCommand, Answer, LibvirtComputingResource> {
4349

50+
private static final List<Storage.StoragePoolType> STORAGE_POOL_TYPES_SUPPORTED = Arrays.asList(Storage.StoragePoolType.Filesystem, Storage.StoragePoolType.NetworkFilesystem);
51+
4452
@Override
4553
public Answer execute(final CheckVolumeCommand command, final LibvirtComputingResource libvirtComputingResource) {
4654
String result = null;
@@ -50,34 +58,76 @@ public Answer execute(final CheckVolumeCommand command, final LibvirtComputingRe
5058
KVMStoragePool pool = poolMgr.getStoragePool(storageFilerTO.getType(), storageFilerTO.getUuid());
5159

5260
try {
53-
if (storageFilerTO.getType() == Storage.StoragePoolType.Filesystem ||
54-
storageFilerTO.getType() == Storage.StoragePoolType.NetworkFilesystem) {
61+
if (STORAGE_POOL_TYPES_SUPPORTED.contains(storageFilerTO.getType())) {
5562
final KVMPhysicalDisk vol = pool.getPhysicalDisk(srcFile);
5663
final String path = vol.getPath();
57-
long size = getVirtualSizeFromFile(path);
58-
return new CheckVolumeAnswer(command, "", size);
64+
try {
65+
KVMPhysicalDisk.checkQcow2File(path);
66+
} catch (final CloudRuntimeException e) {
67+
return new CheckVolumeAnswer(command, false, "", 0, getVolumeDetails(pool, vol));
68+
}
69+
70+
long size = KVMPhysicalDisk.getVirtualSizeFromFile(path);
71+
return new CheckVolumeAnswer(command, true, "", size, getVolumeDetails(pool, vol));
5972
} else {
6073
return new Answer(command, false, "Unsupported Storage Pool");
6174
}
62-
6375
} catch (final Exception e) {
64-
logger.error("Error while locating disk: "+ e.getMessage());
76+
logger.error("Error while locating disk: {}", e.getMessage());
6577
return new Answer(command, false, result);
6678
}
6779
}
6880

69-
private long getVirtualSizeFromFile(String path) {
81+
private Map<VolumeOnStorageTO.Detail, String> getVolumeDetails(KVMStoragePool pool, KVMPhysicalDisk disk) {
82+
Map<String, String> info = getDiskFileInfo(pool, disk, true);
83+
if (MapUtils.isEmpty(info)) {
84+
return null;
85+
}
86+
87+
Map<VolumeOnStorageTO.Detail, String> volumeDetails = new HashMap<>();
88+
89+
String backingFilePath = info.get(QemuImg.BACKING_FILE);
90+
if (StringUtils.isNotBlank(backingFilePath)) {
91+
volumeDetails.put(VolumeOnStorageTO.Detail.BACKING_FILE, backingFilePath);
92+
}
93+
String backingFileFormat = info.get(QemuImg.BACKING_FILE_FORMAT);
94+
if (StringUtils.isNotBlank(backingFileFormat)) {
95+
volumeDetails.put(VolumeOnStorageTO.Detail.BACKING_FILE_FORMAT, backingFileFormat);
96+
}
97+
String clusterSize = info.get(QemuImg.CLUSTER_SIZE);
98+
if (StringUtils.isNotBlank(clusterSize)) {
99+
volumeDetails.put(VolumeOnStorageTO.Detail.CLUSTER_SIZE, clusterSize);
100+
}
101+
String fileFormat = info.get(QemuImg.FILE_FORMAT);
102+
if (StringUtils.isNotBlank(fileFormat)) {
103+
volumeDetails.put(VolumeOnStorageTO.Detail.FILE_FORMAT, fileFormat);
104+
}
105+
String encrypted = info.get(QemuImg.ENCRYPTED);
106+
if (StringUtils.isNotBlank(encrypted) && encrypted.equalsIgnoreCase("yes")) {
107+
volumeDetails.put(VolumeOnStorageTO.Detail.IS_ENCRYPTED, String.valueOf(Boolean.TRUE));
108+
}
109+
Boolean isLocked = isDiskFileLocked(pool, disk);
110+
volumeDetails.put(VolumeOnStorageTO.Detail.IS_LOCKED, String.valueOf(isLocked));
111+
112+
return volumeDetails;
113+
}
114+
115+
private Map<String, String> getDiskFileInfo(KVMStoragePool pool, KVMPhysicalDisk disk, boolean secure) {
116+
if (!STORAGE_POOL_TYPES_SUPPORTED.contains(pool.getType())) {
117+
return new HashMap<>(); // unknown
118+
}
70119
try {
71120
QemuImg qemu = new QemuImg(0);
72-
QemuImgFile qemuFile = new QemuImgFile(path);
73-
Map<String, String> info = qemu.info(qemuFile);
74-
if (info.containsKey(QemuImg.VIRTUAL_SIZE)) {
75-
return Long.parseLong(info.get(QemuImg.VIRTUAL_SIZE));
76-
} else {
77-
throw new CloudRuntimeException("Unable to determine virtual size of volume at path " + path);
78-
}
121+
QemuImgFile qemuFile = new QemuImgFile(disk.getPath(), disk.getFormat());
122+
return qemu.info(qemuFile, secure);
79123
} catch (QemuImgException | LibvirtException ex) {
80-
throw new CloudRuntimeException("Error when inspecting volume at path " + path, ex);
124+
logger.error("Failed to get info of disk file: " + ex.getMessage());
125+
return null;
81126
}
82127
}
128+
129+
private boolean isDiskFileLocked(KVMStoragePool pool, KVMPhysicalDisk disk) {
130+
Map<String, String> info = getDiskFileInfo(pool, disk, false);
131+
return info == null;
132+
}
83133
}

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCopyRemoteVolumeCommandWrapper.java

Lines changed: 66 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,24 @@
3131
import com.cloud.resource.ResourceWrapper;
3232
import com.cloud.storage.Storage;
3333
import com.cloud.utils.exception.CloudRuntimeException;
34+
import org.apache.cloudstack.storage.volume.VolumeOnStorageTO;
3435
import org.apache.cloudstack.utils.qemu.QemuImg;
3536
import org.apache.cloudstack.utils.qemu.QemuImgException;
3637
import org.apache.cloudstack.utils.qemu.QemuImgFile;
38+
import org.apache.commons.collections.MapUtils;
39+
import org.apache.commons.lang3.StringUtils;
3740
import org.libvirt.LibvirtException;
3841

42+
import java.util.Arrays;
43+
import java.util.HashMap;
44+
import java.util.List;
3945
import java.util.Map;
4046

4147
@ResourceWrapper(handles = CopyRemoteVolumeCommand.class)
4248
public final class LibvirtCopyRemoteVolumeCommandWrapper extends CommandWrapper<CopyRemoteVolumeCommand, Answer, LibvirtComputingResource> {
4349

50+
private static final List<Storage.StoragePoolType> STORAGE_POOL_TYPES_SUPPORTED = Arrays.asList(Storage.StoragePoolType.Filesystem, Storage.StoragePoolType.NetworkFilesystem);
51+
4452
@Override
4553
public Answer execute(final CopyRemoteVolumeCommand command, final LibvirtComputingResource libvirtComputingResource) {
4654
String srcIp = command.getRemoteIp();
@@ -55,37 +63,80 @@ public Answer execute(final CopyRemoteVolumeCommand command, final LibvirtComput
5563
int timeoutInSecs = command.getWait();
5664

5765
try {
58-
if (storageFilerTO.getType() == Storage.StoragePoolType.Filesystem ||
59-
storageFilerTO.getType() == Storage.StoragePoolType.NetworkFilesystem) {
66+
if (STORAGE_POOL_TYPES_SUPPORTED.contains(storageFilerTO.getType())) {
6067
String filename = libvirtComputingResource.copyVolume(srcIp, username, password, dstPath, srcFile, tmpPath, timeoutInSecs);
61-
logger.debug("Volume " + srcFile + " copy successful, copied to file: " + filename);
68+
logger.debug("Volume {} copy successful, copied to file: {}", srcFile, filename);
6269
final KVMPhysicalDisk vol = pool.getPhysicalDisk(filename);
6370
final String path = vol.getPath();
64-
long size = getVirtualSizeFromFile(path);
65-
return new CopyRemoteVolumeAnswer(command, "", filename, size);
71+
try {
72+
KVMPhysicalDisk.checkQcow2File(path);
73+
} catch (final CloudRuntimeException e) {
74+
return new CopyRemoteVolumeAnswer(command, false, "", filename, 0, getVolumeDetails(pool, vol));
75+
}
76+
77+
long size = KVMPhysicalDisk.getVirtualSizeFromFile(path);
78+
return new CopyRemoteVolumeAnswer(command, true, "", filename, size, getVolumeDetails(pool, vol));
6679
} else {
6780
String msg = "Unsupported storage pool type: " + storageFilerTO.getType().toString() + ", only local and NFS pools are supported";
6881
return new Answer(command, false, msg);
6982
}
7083
} catch (final Exception e) {
71-
logger.error("Error while copying volume file from remote host: " + e.getMessage(), e);
84+
logger.error("Error while copying volume file from remote host: {}", e.getMessage(), e);
7285
String msg = "Failed to copy volume due to: " + e.getMessage();
7386
return new Answer(command, false, msg);
7487
}
7588
}
7689

77-
private long getVirtualSizeFromFile(String path) {
90+
private Map<VolumeOnStorageTO.Detail, String> getVolumeDetails(KVMStoragePool pool, KVMPhysicalDisk disk) {
91+
Map<String, String> info = getDiskFileInfo(pool, disk, true);
92+
if (MapUtils.isEmpty(info)) {
93+
return null;
94+
}
95+
96+
Map<VolumeOnStorageTO.Detail, String> volumeDetails = new HashMap<>();
97+
98+
String backingFilePath = info.get(QemuImg.BACKING_FILE);
99+
if (StringUtils.isNotBlank(backingFilePath)) {
100+
volumeDetails.put(VolumeOnStorageTO.Detail.BACKING_FILE, backingFilePath);
101+
}
102+
String backingFileFormat = info.get(QemuImg.BACKING_FILE_FORMAT);
103+
if (StringUtils.isNotBlank(backingFileFormat)) {
104+
volumeDetails.put(VolumeOnStorageTO.Detail.BACKING_FILE_FORMAT, backingFileFormat);
105+
}
106+
String clusterSize = info.get(QemuImg.CLUSTER_SIZE);
107+
if (StringUtils.isNotBlank(clusterSize)) {
108+
volumeDetails.put(VolumeOnStorageTO.Detail.CLUSTER_SIZE, clusterSize);
109+
}
110+
String fileFormat = info.get(QemuImg.FILE_FORMAT);
111+
if (StringUtils.isNotBlank(fileFormat)) {
112+
volumeDetails.put(VolumeOnStorageTO.Detail.FILE_FORMAT, fileFormat);
113+
}
114+
String encrypted = info.get(QemuImg.ENCRYPTED);
115+
if (StringUtils.isNotBlank(encrypted) && encrypted.equalsIgnoreCase("yes")) {
116+
volumeDetails.put(VolumeOnStorageTO.Detail.IS_ENCRYPTED, String.valueOf(Boolean.TRUE));
117+
}
118+
Boolean isLocked = isDiskFileLocked(pool, disk);
119+
volumeDetails.put(VolumeOnStorageTO.Detail.IS_LOCKED, String.valueOf(isLocked));
120+
121+
return volumeDetails;
122+
}
123+
124+
private Map<String, String> getDiskFileInfo(KVMStoragePool pool, KVMPhysicalDisk disk, boolean secure) {
125+
if (!STORAGE_POOL_TYPES_SUPPORTED.contains(pool.getType())) {
126+
return new HashMap<>(); // unknown
127+
}
78128
try {
79129
QemuImg qemu = new QemuImg(0);
80-
QemuImgFile qemuFile = new QemuImgFile(path);
81-
Map<String, String> info = qemu.info(qemuFile);
82-
if (info.containsKey(QemuImg.VIRTUAL_SIZE)) {
83-
return Long.parseLong(info.get(QemuImg.VIRTUAL_SIZE));
84-
} else {
85-
throw new CloudRuntimeException("Unable to determine virtual size of volume at path " + path);
86-
}
130+
QemuImgFile qemuFile = new QemuImgFile(disk.getPath(), disk.getFormat());
131+
return qemu.info(qemuFile, secure);
87132
} catch (QemuImgException | LibvirtException ex) {
88-
throw new CloudRuntimeException("Error when inspecting volume at path " + path, ex);
133+
logger.error("Failed to get info of disk file: {}", ex.getMessage());
134+
return null;
89135
}
90136
}
137+
138+
private boolean isDiskFileLocked(KVMStoragePool pool, KVMPhysicalDisk disk) {
139+
Map<String, String> info = getDiskFileInfo(pool, disk, false);
140+
return info == null;
141+
}
91142
}

0 commit comments

Comments
 (0)