Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions core/src/main/java/com/cloud/agent/api/CheckVolumeAnswer.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,33 @@

package com.cloud.agent.api;

import org.apache.cloudstack.storage.volume.VolumeOnStorageTO;

import java.util.Map;

public class CheckVolumeAnswer extends Answer {

private long size;
private Map<VolumeOnStorageTO.Detail, String> volumeDetails;

CheckVolumeAnswer() {
}

public CheckVolumeAnswer(CheckVolumeCommand cmd, String details, long size) {
super(cmd, true, details);
public CheckVolumeAnswer(CheckVolumeCommand cmd, final boolean success, String details, long size,
Map<VolumeOnStorageTO.Detail, String> volumeDetails) {
super(cmd, success, details);
this.size = size;
this.volumeDetails = volumeDetails;
}

public long getSize() {
return size;
}

public Map<VolumeOnStorageTO.Detail, String> getVolumeDetails() {
return volumeDetails;
}

public String getString() {
return "CheckVolumeAnswer [size=" + size + "]";
}
Expand Down
15 changes: 13 additions & 2 deletions core/src/main/java/com/cloud/agent/api/CopyRemoteVolumeAnswer.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,28 @@

package com.cloud.agent.api;

import org.apache.cloudstack.storage.volume.VolumeOnStorageTO;

import java.util.Map;

public class CopyRemoteVolumeAnswer extends Answer {

private String remoteIp;
private String filename;

private long size;
private Map<VolumeOnStorageTO.Detail, String> volumeDetails;

CopyRemoteVolumeAnswer() {
}

public CopyRemoteVolumeAnswer(CopyRemoteVolumeCommand cmd, String details, String filename, long size) {
super(cmd, true, details);
public CopyRemoteVolumeAnswer(CopyRemoteVolumeCommand cmd, final boolean success, String details, String filename, long size,
Map<VolumeOnStorageTO.Detail, String> volumeDetails) {
super(cmd, success, details);
this.remoteIp = cmd.getRemoteIp();
this.filename = filename;
this.size = size;
this.volumeDetails = volumeDetails;
}

public String getRemoteIp() {
Expand All @@ -54,6 +61,10 @@ public long getSize() {
return size;
}

public Map<VolumeOnStorageTO.Detail, String> getVolumeDetails() {
return volumeDetails;
}

public String getString() {
return "CopyRemoteVolumeAnswer [remoteIp=" + remoteIp + "]";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,25 @@
import com.cloud.resource.ResourceWrapper;
import com.cloud.storage.Storage;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.storage.volume.VolumeOnStorageTO;
import org.apache.cloudstack.utils.qemu.QemuImg;
import org.apache.cloudstack.utils.qemu.QemuImgException;
import org.apache.cloudstack.utils.qemu.QemuImgFile;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.libvirt.LibvirtException;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

private static final Logger s_logger = Logger.getLogger(LibvirtCheckVolumeCommandWrapper.class);
private static final List<Storage.StoragePoolType> STORAGE_POOL_TYPES_SUPPORTED = Arrays.asList(Storage.StoragePoolType.Filesystem, Storage.StoragePoolType.NetworkFilesystem);

@Override
public Answer execute(final CheckVolumeCommand command, final LibvirtComputingResource libvirtComputingResource) {
Expand All @@ -53,34 +60,76 @@ public Answer execute(final CheckVolumeCommand command, final LibvirtComputingRe
KVMStoragePool pool = poolMgr.getStoragePool(storageFilerTO.getType(), storageFilerTO.getUuid());

try {
if (storageFilerTO.getType() == Storage.StoragePoolType.Filesystem ||
storageFilerTO.getType() == Storage.StoragePoolType.NetworkFilesystem) {
if (STORAGE_POOL_TYPES_SUPPORTED.contains(storageFilerTO.getType())) {
final KVMPhysicalDisk vol = pool.getPhysicalDisk(srcFile);
final String path = vol.getPath();
long size = getVirtualSizeFromFile(path);
return new CheckVolumeAnswer(command, "", size);
try {
KVMPhysicalDisk.checkQcow2File(path);
} catch (final CloudRuntimeException e) {
return new CheckVolumeAnswer(command, false, "", 0, getVolumeDetails(pool, vol));
}

long size = KVMPhysicalDisk.getVirtualSizeFromFile(path);
return new CheckVolumeAnswer(command, true, "", size, getVolumeDetails(pool, vol));
} else {
return new Answer(command, false, "Unsupported Storage Pool");
}

} catch (final Exception e) {
s_logger.error("Error while locating disk: "+ e.getMessage());
s_logger.error("Error while checking the disk: " + e.getMessage());
return new Answer(command, false, result);
}
}

private long getVirtualSizeFromFile(String path) {
private Map<VolumeOnStorageTO.Detail, String> getVolumeDetails(KVMStoragePool pool, KVMPhysicalDisk disk) {
Map<String, String> info = getDiskFileInfo(pool, disk, true);
if (MapUtils.isEmpty(info)) {
return null;
}

Map<VolumeOnStorageTO.Detail, String> volumeDetails = new HashMap<>();

String backingFilePath = info.get(QemuImg.BACKING_FILE);
if (StringUtils.isNotBlank(backingFilePath)) {
volumeDetails.put(VolumeOnStorageTO.Detail.BACKING_FILE, backingFilePath);
}
String backingFileFormat = info.get(QemuImg.BACKING_FILE_FORMAT);
if (StringUtils.isNotBlank(backingFileFormat)) {
volumeDetails.put(VolumeOnStorageTO.Detail.BACKING_FILE_FORMAT, backingFileFormat);
}
String clusterSize = info.get(QemuImg.CLUSTER_SIZE);
if (StringUtils.isNotBlank(clusterSize)) {
volumeDetails.put(VolumeOnStorageTO.Detail.CLUSTER_SIZE, clusterSize);
}
String fileFormat = info.get(QemuImg.FILE_FORMAT);
if (StringUtils.isNotBlank(fileFormat)) {
volumeDetails.put(VolumeOnStorageTO.Detail.FILE_FORMAT, fileFormat);
}
String encrypted = info.get(QemuImg.ENCRYPTED);
if (StringUtils.isNotBlank(encrypted) && encrypted.equalsIgnoreCase("yes")) {
volumeDetails.put(VolumeOnStorageTO.Detail.IS_ENCRYPTED, String.valueOf(Boolean.TRUE));
}
Boolean isLocked = isDiskFileLocked(pool, disk);
volumeDetails.put(VolumeOnStorageTO.Detail.IS_LOCKED, String.valueOf(isLocked));

return volumeDetails;
}

private Map<String, String> getDiskFileInfo(KVMStoragePool pool, KVMPhysicalDisk disk, boolean secure) {
if (!STORAGE_POOL_TYPES_SUPPORTED.contains(pool.getType())) {
return new HashMap<>(); // unknown
}
try {
QemuImg qemu = new QemuImg(0);
QemuImgFile qemuFile = new QemuImgFile(path);
Map<String, String> info = qemu.info(qemuFile);
if (info.containsKey(QemuImg.VIRTUAL_SIZE)) {
return Long.parseLong(info.get(QemuImg.VIRTUAL_SIZE));
} else {
throw new CloudRuntimeException("Unable to determine virtual size of volume at path " + path);
}
QemuImgFile qemuFile = new QemuImgFile(disk.getPath(), disk.getFormat());
return qemu.info(qemuFile, secure);
} catch (QemuImgException | LibvirtException ex) {
throw new CloudRuntimeException("Error when inspecting volume at path " + path, ex);
logger.error("Failed to get info of disk file: " + ex.getMessage());
return null;
}
}

private boolean isDiskFileLocked(KVMStoragePool pool, KVMPhysicalDisk disk) {
Map<String, String> info = getDiskFileInfo(pool, disk, false);
return info == null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,25 @@
import com.cloud.resource.ResourceWrapper;
import com.cloud.storage.Storage;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.storage.volume.VolumeOnStorageTO;
import org.apache.cloudstack.utils.qemu.QemuImg;
import org.apache.cloudstack.utils.qemu.QemuImgException;
import org.apache.cloudstack.utils.qemu.QemuImgFile;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.libvirt.LibvirtException;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

private static final Logger s_logger = Logger.getLogger(LibvirtCopyRemoteVolumeCommandWrapper.class);
private static final List<Storage.StoragePoolType> STORAGE_POOL_TYPES_SUPPORTED = Arrays.asList(Storage.StoragePoolType.Filesystem, Storage.StoragePoolType.NetworkFilesystem);

@Override
public Answer execute(final CopyRemoteVolumeCommand command, final LibvirtComputingResource libvirtComputingResource) {
Expand All @@ -58,14 +65,19 @@ public Answer execute(final CopyRemoteVolumeCommand command, final LibvirtComput
int timeoutInSecs = command.getWait();

try {
if (storageFilerTO.getType() == Storage.StoragePoolType.Filesystem ||
storageFilerTO.getType() == Storage.StoragePoolType.NetworkFilesystem) {
if (STORAGE_POOL_TYPES_SUPPORTED.contains(storageFilerTO.getType())) {
String filename = libvirtComputingResource.copyVolume(srcIp, username, password, dstPath, srcFile, tmpPath, timeoutInSecs);
s_logger.debug("Volume " + srcFile + " copy successful, copied to file: " + filename);
final KVMPhysicalDisk vol = pool.getPhysicalDisk(filename);
final String path = vol.getPath();
long size = getVirtualSizeFromFile(path);
return new CopyRemoteVolumeAnswer(command, "", filename, size);
try {
KVMPhysicalDisk.checkQcow2File(path);
} catch (final CloudRuntimeException e) {
return new CopyRemoteVolumeAnswer(command, false, "", filename, 0, getVolumeDetails(pool, vol));
}

long size = KVMPhysicalDisk.getVirtualSizeFromFile(path);
return new CopyRemoteVolumeAnswer(command, true, "", filename, size, getVolumeDetails(pool, vol));
} else {
String msg = "Unsupported storage pool type: " + storageFilerTO.getType().toString() + ", only local and NFS pools are supported";
return new Answer(command, false, msg);
Expand All @@ -77,18 +89,56 @@ public Answer execute(final CopyRemoteVolumeCommand command, final LibvirtComput
}
}

private long getVirtualSizeFromFile(String path) {
private Map<VolumeOnStorageTO.Detail, String> getVolumeDetails(KVMStoragePool pool, KVMPhysicalDisk disk) {
Map<String, String> info = getDiskFileInfo(pool, disk, true);
if (MapUtils.isEmpty(info)) {
return null;
}

Map<VolumeOnStorageTO.Detail, String> volumeDetails = new HashMap<>();

String backingFilePath = info.get(QemuImg.BACKING_FILE);
if (StringUtils.isNotBlank(backingFilePath)) {
volumeDetails.put(VolumeOnStorageTO.Detail.BACKING_FILE, backingFilePath);
}
String backingFileFormat = info.get(QemuImg.BACKING_FILE_FORMAT);
if (StringUtils.isNotBlank(backingFileFormat)) {
volumeDetails.put(VolumeOnStorageTO.Detail.BACKING_FILE_FORMAT, backingFileFormat);
}
String clusterSize = info.get(QemuImg.CLUSTER_SIZE);
if (StringUtils.isNotBlank(clusterSize)) {
volumeDetails.put(VolumeOnStorageTO.Detail.CLUSTER_SIZE, clusterSize);
}
String fileFormat = info.get(QemuImg.FILE_FORMAT);
if (StringUtils.isNotBlank(fileFormat)) {
volumeDetails.put(VolumeOnStorageTO.Detail.FILE_FORMAT, fileFormat);
}
String encrypted = info.get(QemuImg.ENCRYPTED);
if (StringUtils.isNotBlank(encrypted) && encrypted.equalsIgnoreCase("yes")) {
volumeDetails.put(VolumeOnStorageTO.Detail.IS_ENCRYPTED, String.valueOf(Boolean.TRUE));
}
Boolean isLocked = isDiskFileLocked(pool, disk);
volumeDetails.put(VolumeOnStorageTO.Detail.IS_LOCKED, String.valueOf(isLocked));

return volumeDetails;
}

private Map<String, String> getDiskFileInfo(KVMStoragePool pool, KVMPhysicalDisk disk, boolean secure) {
if (!STORAGE_POOL_TYPES_SUPPORTED.contains(pool.getType())) {
return new HashMap<>(); // unknown
}
try {
QemuImg qemu = new QemuImg(0);
QemuImgFile qemuFile = new QemuImgFile(path);
Map<String, String> info = qemu.info(qemuFile);
if (info.containsKey(QemuImg.VIRTUAL_SIZE)) {
return Long.parseLong(info.get(QemuImg.VIRTUAL_SIZE));
} else {
throw new CloudRuntimeException("Unable to determine virtual size of volume at path " + path);
}
QemuImgFile qemuFile = new QemuImgFile(disk.getPath(), disk.getFormat());
return qemu.info(qemuFile, secure);
} catch (QemuImgException | LibvirtException ex) {
throw new CloudRuntimeException("Error when inspecting volume at path " + path, ex);
logger.error("Failed to get info of disk file: " + ex.getMessage());
return null;
}
}

private boolean isDiskFileLocked(KVMStoragePool pool, KVMPhysicalDisk disk) {
Map<String, String> info = getDiskFileInfo(pool, disk, false);
return info == null;
}
}
Loading
Loading