use of com.cloud.agent.api.storage.ResizeVolumeAnswer in project cloudstack by apache.
the class VmwareResource method execute.
private Answer execute(ResizeVolumeCommand cmd) {
String path = cmd.getPath();
String vmName = cmd.getInstanceName();
long newSize = cmd.getNewSize() / ResourceType.bytesToKiB;
long oldSize = cmd.getCurrentSize() / ResourceType.bytesToKiB;
boolean managed = cmd.isManaged();
String poolUUID = cmd.getPoolUuid();
String chainInfo = cmd.getChainInfo();
boolean useWorkerVm = false;
VmwareContext context = getServiceContext();
VmwareHypervisorHost hyperHost = getHyperHost(context);
VirtualMachineMO vmMo = null;
String vmdkDataStorePath = null;
try {
if (newSize < oldSize) {
String errorMsg = String.format("VMware doesn't support shrinking volume from larger size [%s] GB to a smaller size [%s] GB. Can't resize volume of VM [name: %s].", oldSize / Float.valueOf(ResourceType.bytesToMiB), newSize / Float.valueOf(ResourceType.bytesToMiB), vmName);
s_logger.error(errorMsg);
throw new Exception(errorMsg);
} else if (newSize == oldSize) {
return new ResizeVolumeAnswer(cmd, true, "success", newSize * ResourceType.bytesToKiB);
}
if (vmName.equalsIgnoreCase("none")) {
// OfflineVmwareMigration: we need to refactor the worker vm creation out for use in migration methods as well as here
// OfflineVmwareMigration: this method is 100 lines and needs refactorring anyway
// we need to spawn a worker VM to attach the volume to and resize the volume.
useWorkerVm = true;
String poolId = cmd.getPoolUuid();
// OfflineVmwareMigration: refactor for re-use
// OfflineVmwareMigration: 1. find data(store)
ManagedObjectReference morDS = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, poolId);
DatastoreMO dsMo = new DatastoreMO(hyperHost.getContext(), morDS);
vmName = getWorkerName(getServiceContext(), cmd, 0, dsMo);
s_logger.info("Create worker VM " + vmName);
// OfflineVmwareMigration: 2. create the worker with access to the data(store)
vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, vmName, null);
if (vmMo == null) {
// OfflineVmwareMigration: don't throw a general Exception but think of a specific one
throw new Exception("Unable to create a worker VM for volume resize");
}
synchronized (this) {
// OfflineVmwareMigration: 3. attach the disk to the worker
vmdkDataStorePath = VmwareStorageLayoutHelper.getLegacyDatastorePathFromVmdkFileName(dsMo, path + VMDK_EXTENSION);
vmMo.attachDisk(new String[] { vmdkDataStorePath }, morDS);
}
}
// OfflineVmwareMigration: 4. find the (worker-) VM
// find VM through datacenter (VM is not at the target host yet)
vmMo = hyperHost.findVmOnPeerHyperHost(vmName);
if (vmMo == null) {
String errorMsg = String.format("VM [name: %s] does not exist in VMware datacenter.", vmName);
s_logger.error(errorMsg);
throw new Exception(errorMsg);
}
if (managed) {
ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
ClusterMO clusterMO = new ClusterMO(context, morCluster);
List<Pair<ManagedObjectReference, String>> lstHosts = clusterMO.getClusterHosts();
Collections.shuffle(lstHosts, RANDOM);
Pair<ManagedObjectReference, String> host = lstHosts.get(0);
HostMO hostMO = new HostMO(context, host.first());
HostDatastoreSystemMO hostDatastoreSystem = hostMO.getHostDatastoreSystemMO();
String iScsiName = cmd.get_iScsiName();
ManagedObjectReference morDS = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, VmwareResource.getDatastoreName(iScsiName));
DatastoreMO dsMo = new DatastoreMO(hyperHost.getContext(), morDS);
_storageProcessor.expandDatastore(hostDatastoreSystem, dsMo);
}
boolean volumePathChangeObserved = false;
boolean datastoreChangeObserved = false;
Pair<String, String> pathAndChainInfo = getNewPathAndChainInfoInDatastoreCluster(vmMo, path, chainInfo, managed, cmd.get_iScsiName(), poolUUID, cmd.getContextParam(DiskTO.PROTOCOL_TYPE));
Pair<String, String> poolUUIDandChainInfo = getNewPoolUUIDAndChainInfoInDatastoreCluster(vmMo, path, chainInfo, managed, cmd.get_iScsiName(), poolUUID, cmd.getContextParam(DiskTO.PROTOCOL_TYPE));
if (pathAndChainInfo != null) {
volumePathChangeObserved = true;
path = pathAndChainInfo.first();
chainInfo = pathAndChainInfo.second();
}
if (poolUUIDandChainInfo != null) {
datastoreChangeObserved = true;
poolUUID = poolUUIDandChainInfo.first();
chainInfo = poolUUIDandChainInfo.second();
}
// OfflineVmwareMigration: 5. ignore/replace the rest of the try-block; It is the functional bit
VirtualDisk disk = getDiskAfterResizeDiskValidations(vmMo, path);
String vmdkAbsFile = getAbsoluteVmdkFile(disk);
if (vmdkAbsFile != null && !vmdkAbsFile.isEmpty()) {
vmMo.updateAdapterTypeIfRequired(vmdkAbsFile);
}
disk.setCapacityInKB(newSize);
VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();
deviceConfigSpec.setDevice(disk);
deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.EDIT);
VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec();
vmConfigSpec.getDeviceChange().add(deviceConfigSpec);
if (!vmMo.configureVm(vmConfigSpec)) {
throw new Exception(String.format("Failed to configure VM [name: %s] to resize disk.", vmName));
}
ResizeVolumeAnswer answer = new ResizeVolumeAnswer(cmd, true, "success", newSize * 1024);
if (datastoreChangeObserved) {
answer.setContextParam("datastoreUUID", poolUUID);
answer.setContextParam("chainInfo", chainInfo);
}
if (volumePathChangeObserved) {
answer.setContextParam("volumePath", path);
answer.setContextParam("chainInfo", chainInfo);
}
return answer;
} catch (Exception e) {
String errorMsg = String.format("Failed to resize volume of VM [name: %s] due to: [%s].", vmName, e.getMessage());
s_logger.error(errorMsg, e);
return new ResizeVolumeAnswer(cmd, false, errorMsg);
} finally {
// OfflineVmwareMigration: 6. check if a worker was used and destroy it if needed
try {
if (useWorkerVm) {
s_logger.info("Destroy worker VM after volume resize");
vmMo.detachDisk(vmdkDataStorePath, false);
vmMo.destroy();
}
} catch (Throwable e) {
s_logger.error(String.format("Failed to destroy worker VM [name: %s] due to: [%s].", vmName, e.getMessage()), e);
}
}
}
use of com.cloud.agent.api.storage.ResizeVolumeAnswer in project cloudstack by apache.
the class LibvirtResizeVolumeCommandWrapper method execute.
@Override
public Answer execute(final ResizeVolumeCommand command, final LibvirtComputingResource libvirtComputingResource) {
final String volid = command.getPath();
final long newSize = command.getNewSize();
final long currentSize = command.getCurrentSize();
final String vmInstanceName = command.getInstanceName();
final boolean shrinkOk = command.getShrinkOk();
final StorageFilerTO spool = command.getPool();
final String notifyOnlyType = LibvirtComputingResource.RESIZE_NOTIFY_ONLY;
if (currentSize == newSize) {
// nothing to do
s_logger.info("No need to resize volume: current size " + toHumanReadableSize(currentSize) + " is same as new size " + toHumanReadableSize(newSize));
return new ResizeVolumeAnswer(command, true, "success", currentSize);
}
try {
final KVMStoragePoolManager storagePoolMgr = libvirtComputingResource.getStoragePoolMgr();
KVMStoragePool pool = storagePoolMgr.getStoragePool(spool.getType(), spool.getUuid());
final KVMPhysicalDisk vol = pool.getPhysicalDisk(volid);
final String path = vol.getPath();
String type = notifyOnlyType;
if (pool.getType() != StoragePoolType.RBD && pool.getType() != StoragePoolType.Linstor) {
type = libvirtComputingResource.getResizeScriptType(pool, vol);
if (type.equals("QCOW2") && shrinkOk) {
return new ResizeVolumeAnswer(command, false, "Unable to shrink volumes of type " + type);
}
} else {
s_logger.debug("Volume " + path + " is on a RBD/Linstor storage pool. No need to query for additional information.");
}
s_logger.debug("Resizing volume: " + path + ", from: " + toHumanReadableSize(currentSize) + ", to: " + toHumanReadableSize(newSize) + ", type: " + type + ", name: " + vmInstanceName + ", shrinkOk: " + shrinkOk);
/* libvirt doesn't support resizing (C)LVM devices, and corrupts QCOW2 in some scenarios, so we have to do these via Bash script */
if (pool.getType() != StoragePoolType.CLVM && pool.getType() != StoragePoolType.Linstor && vol.getFormat() != PhysicalDiskFormat.QCOW2) {
s_logger.debug("Volume " + path + " can be resized by libvirt. Asking libvirt to resize the volume.");
try {
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper();
final Connect conn = libvirtUtilitiesHelper.getConnection();
final StorageVol v = conn.storageVolLookupByPath(path);
int flags = 0;
if (conn.getLibVirVersion() > 1001000 && vol.getFormat() == PhysicalDiskFormat.RAW && pool.getType() != StoragePoolType.RBD) {
flags = 1;
}
if (shrinkOk) {
flags = 4;
}
v.resize(newSize, flags);
} catch (final LibvirtException e) {
return new ResizeVolumeAnswer(command, false, e.toString());
}
}
s_logger.debug("Invoking resize script to handle type " + type);
final Script resizecmd = new Script(libvirtComputingResource.getResizeVolumePath(), libvirtComputingResource.getCmdsTimeout(), s_logger);
resizecmd.add("-s", String.valueOf(newSize));
resizecmd.add("-c", String.valueOf(currentSize));
resizecmd.add("-p", path);
resizecmd.add("-t", type);
resizecmd.add("-r", String.valueOf(shrinkOk));
resizecmd.add("-v", vmInstanceName);
final String result = resizecmd.execute();
if (result != null) {
if (type.equals(notifyOnlyType)) {
return new ResizeVolumeAnswer(command, true, "Resize succeeded, but need reboot to notify guest");
} else {
return new ResizeVolumeAnswer(command, false, result);
}
}
/* fetch new size as seen from libvirt, don't want to assume anything */
pool = storagePoolMgr.getStoragePool(spool.getType(), spool.getUuid());
pool.refresh();
final long finalSize = pool.getPhysicalDisk(volid).getVirtualSize();
s_logger.debug("after resize, size reports as: " + toHumanReadableSize(finalSize) + ", requested: " + toHumanReadableSize(newSize));
return new ResizeVolumeAnswer(command, true, "success", finalSize);
} catch (final CloudRuntimeException e) {
final String error = "Failed to resize volume: " + e.getMessage();
s_logger.debug(error);
return new ResizeVolumeAnswer(command, false, error);
}
}
use of com.cloud.agent.api.storage.ResizeVolumeAnswer in project cloudstack by apache.
the class CitrixResizeVolumeCommandWrapper method execute.
@Override
public Answer execute(final ResizeVolumeCommand command, final CitrixResourceBase citrixResourceBase) {
Connection conn = citrixResourceBase.getConnection();
String volId = command.getPath();
long newSize = command.getNewSize();
try {
if (command.getCurrentSize() >= newSize) {
s_logger.info("No need to resize volume: " + volId + ", current size " + toHumanReadableSize(command.getCurrentSize()) + " is same as new size " + toHumanReadableSize(newSize));
return new ResizeVolumeAnswer(command, true, "success", newSize);
}
if (command.isManaged()) {
resizeSr(conn, command);
}
VDI vdi = citrixResourceBase.getVDIbyUuid(conn, volId);
vdi.resize(conn, newSize);
return new ResizeVolumeAnswer(command, true, "success", newSize);
} catch (Exception ex) {
s_logger.warn("Unable to resize volume", ex);
String error = "Failed to resize volume: " + ex;
return new ResizeVolumeAnswer(command, false, error);
}
}
use of com.cloud.agent.api.storage.ResizeVolumeAnswer in project cloudstack by apache.
the class CloudStackPrimaryDataStoreDriverImpl method resize.
@Override
public void resize(DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) {
VolumeObject vol = (VolumeObject) data;
StoragePool pool = (StoragePool) data.getDataStore();
ResizeVolumePayload resizeParameter = (ResizeVolumePayload) vol.getpayload();
ResizeVolumeCommand resizeCmd = new ResizeVolumeCommand(vol.getPath(), new StorageFilerTO(pool), vol.getSize(), resizeParameter.newSize, resizeParameter.shrinkOk, resizeParameter.instanceName, vol.getChainInfo());
if (pool.getParent() != 0) {
resizeCmd.setContextParam(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString());
}
CreateCmdResult result = new CreateCmdResult(null, null);
try {
ResizeVolumeAnswer answer = (ResizeVolumeAnswer) storageMgr.sendToPool(pool, resizeParameter.hosts, resizeCmd);
if (answer != null && answer.getResult()) {
long finalSize = answer.getNewSize();
s_logger.debug("Resize: volume started at size: " + toHumanReadableSize(vol.getSize()) + " and ended at size: " + toHumanReadableSize(finalSize));
vol.setSize(finalSize);
vol.update();
updateVolumePathDetails(vol, answer);
} else if (answer != null) {
result.setResult(answer.getDetails());
} else {
s_logger.debug("return a null answer, mark it as failed for unknown reason");
result.setResult("return a null answer, mark it as failed for unknown reason");
}
} catch (Exception e) {
s_logger.debug("sending resize command failed", e);
result.setResult(e.toString());
}
callback.complete(result);
}
use of com.cloud.agent.api.storage.ResizeVolumeAnswer in project cosmic by MissionCriticalCloud.
the class LibvirtResizeVolumeCommandWrapper method execute.
@Override
public Answer execute(final ResizeVolumeCommand command, final LibvirtComputingResource libvirtComputingResource) {
final String volid = command.getPath();
final long newSize = command.getNewSize();
final long currentSize = command.getCurrentSize();
final String vmInstanceName = command.getInstanceName();
final boolean shrinkOk = command.getShrinkOk();
final StorageFilerTO spool = command.getPool();
final String notifyOnlyType = "NOTIFYONLY";
if (currentSize == newSize) {
// nothing to do
s_logger.info("No need to resize volume: current size " + currentSize + " is same as new size " + newSize);
return new ResizeVolumeAnswer(command, true, "success", currentSize);
}
try {
final KvmStoragePoolManager storagePoolMgr = libvirtComputingResource.getStoragePoolMgr();
KvmStoragePool pool = storagePoolMgr.getStoragePool(spool.getType(), spool.getUuid());
final KvmPhysicalDisk vol = pool.getPhysicalDisk(volid);
final String path = vol.getPath();
String type = notifyOnlyType;
if (pool.getType() != StoragePoolType.RBD) {
type = libvirtComputingResource.getResizeScriptType(pool, vol);
if (type.equals("QCOW2") && shrinkOk) {
return new ResizeVolumeAnswer(command, false, "Unable to shrink volumes of type " + type);
}
} else {
s_logger.debug("Volume " + path + " is on a RBD storage pool. No need to query for additional information.");
}
s_logger.debug("Resizing volume: " + path + "," + currentSize + "," + newSize + "," + type + "," + vmInstanceName + "," + shrinkOk);
/*
* libvirt doesn't support resizing (C)LVM devices, and corrupts QCOW2 in some scenarios, so we have to do these
* via Bash script
*/
if (pool.getType() != StoragePoolType.CLVM && vol.getFormat() != PhysicalDiskFormat.QCOW2) {
s_logger.debug("Volume " + path + " can be resized by libvirt. Asking libvirt to resize the volume.");
try {
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper();
final Connect conn = libvirtUtilitiesHelper.getConnection();
final StorageVol v = conn.storageVolLookupByPath(path);
int flags = 0;
if (conn.getLibVirVersion() > 1001000 && vol.getFormat() == PhysicalDiskFormat.RAW && pool.getType() != StoragePoolType.RBD) {
flags = 1;
}
if (shrinkOk) {
flags = 4;
}
v.resize(newSize, flags);
} catch (final LibvirtException e) {
return new ResizeVolumeAnswer(command, false, e.toString());
}
}
s_logger.debug("Invoking resize script to handle type " + type);
final Script resizecmd = new Script(libvirtComputingResource.getResizeVolumePath(), libvirtComputingResource.getCmdsTimeout(), s_logger);
resizecmd.add("-s", String.valueOf(newSize));
resizecmd.add("-c", String.valueOf(currentSize));
resizecmd.add("-p", path);
resizecmd.add("-t", type);
resizecmd.add("-r", String.valueOf(shrinkOk));
resizecmd.add("-v", vmInstanceName);
final String result = resizecmd.execute();
if (result != null) {
if (type.equals(notifyOnlyType)) {
return new ResizeVolumeAnswer(command, true, "Resize succeeded, but need reboot to notify guest");
} else {
return new ResizeVolumeAnswer(command, false, result);
}
}
/* fetch new size as seen from libvirt, don't want to assume anything */
pool = storagePoolMgr.getStoragePool(spool.getType(), spool.getUuid());
pool.refresh();
final long finalSize = pool.getPhysicalDisk(volid).getVirtualSize();
s_logger.debug("after resize, size reports as " + finalSize + ", requested " + newSize);
return new ResizeVolumeAnswer(command, true, "success", finalSize);
} catch (final CloudRuntimeException e) {
final String error = "Failed to resize volume: " + e.getMessage();
s_logger.debug(error);
return new ResizeVolumeAnswer(command, false, error);
}
}
Aggregations