use of com.cloud.agent.resource.kvm.xml.LibvirtDiskDef in project cosmic by MissionCriticalCloud.
the class LibvirtStopCommandWrapper method execute.
@Override
public Answer execute(final StopCommand command, final LibvirtComputingResource libvirtComputingResource) {
final String vmName = command.getVmName();
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper();
if (command.checkBeforeCleanup()) {
try {
final Connect conn = libvirtUtilitiesHelper.getConnectionByVmName(vmName);
final Domain vm = conn.domainLookupByName(command.getVmName());
if (vm != null && vm.getInfo().state == DomainState.VIR_DOMAIN_RUNNING) {
return new StopAnswer(command, "vm is still running on host", false);
}
} catch (final Exception e) {
s_logger.debug("Failed to get vm status in case of checkboforecleanup is true", e);
}
}
try {
final Connect conn = libvirtUtilitiesHelper.getConnectionByVmName(vmName);
final List<LibvirtDiskDef> disks = libvirtComputingResource.getDisks(conn, vmName);
final List<LibvirtVmDef.InterfaceDef> ifaces = libvirtComputingResource.getInterfaces(conn, vmName);
final String result = libvirtComputingResource.stopVm(conn, vmName, command.isForceStop());
if (result == null) {
for (final LibvirtDiskDef disk : disks) {
libvirtComputingResource.cleanupDisk(disk);
}
for (final LibvirtVmDef.InterfaceDef iface : ifaces) {
// each interface at this point, so inform all vif drivers
for (final VifDriver vifDriver : libvirtComputingResource.getAllVifDrivers()) {
vifDriver.unplug(iface);
}
}
}
return new StopAnswer(command, result, true);
} catch (final LibvirtException e) {
return new StopAnswer(command, e.getMessage(), false);
}
}
use of com.cloud.agent.resource.kvm.xml.LibvirtDiskDef in project cosmic by MissionCriticalCloud.
the class LibvirtMigrateVolumeCommandWrapper method execute.
@Override
public Answer execute(final MigrateVolumeCommand command, final LibvirtComputingResource libvirtComputingResource) {
String result = null;
final String vmName = command.getAttachedVmName();
LibvirtDiskDef disk = null;
final List<LibvirtDiskDef> disks;
boolean isMigrationSuccessfull = false;
Domain dm = null;
Connect conn = null;
String currentVolumePath = null;
final String newVolumePath;
final CountDownLatch completeSignal = new CountDownLatch(1);
final BlockJobListener blockJobListener = new BlockJobListener() {
@Override
public void onBlockJobCompleted(final Domain domain, final String disk, final int type) throws LibvirtException {
onBlockJobReady(domain, disk, type);
}
@Override
public void onBlockJobFailed(final Domain domain, final String disk, final int type) throws LibvirtException {
throw new LibvirtException("BlockJobFailed");
}
@Override
public void onBlockJobCanceled(final Domain domain, final String disk, final int type) throws LibvirtException {
throw new LibvirtException("BlockJobCanceled");
}
@Override
public void onBlockJobReady(final Domain domain, final String disk, final int type) throws LibvirtException {
domain.blockJobAbort(disk, DomainBlockJobAbortFlags.VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT);
completeSignal.countDown();
}
};
try {
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper();
conn = libvirtUtilitiesHelper.getConnectionByVmName(vmName);
disks = libvirtComputingResource.getDisks(conn, vmName);
dm = conn.domainLookupByName(vmName);
newVolumePath = "/mnt/" + command.getPool().getUuid() + "/" + command.getVolumePath();
for (final LibvirtDiskDef diskDef : disks) {
if (diskDef.getDiskPath().contains(command.getVolumePath())) {
disk = diskDef;
break;
}
}
logger.debug("Registering block job listener with libvirt for domain " + dm.getName());
dm.addBlockJobListener(blockJobListener);
if (disk != null) {
currentVolumePath = disk.getDiskPath();
int blockCopySpeed = libvirtComputingResource.getVmBlockCopySpeed();
disk.setDiskPath(newVolumePath);
DomainBlockCopyParameters domainBlockCopyParameters = new DomainBlockCopyParameters();
domainBlockCopyParameters.setDomainBlockCopyBandwidth(blockCopySpeed);
String scale = new String(domainBlockCopyParameters.isDomainBlockCopyBytes() ? " Bytes/s" : " MiB/s");
logger.debug("Starting block copy for domain " + dm.getName() + " from " + currentVolumePath + " to " + newVolumePath + " @ " + blockCopySpeed + scale);
dm.blockCopy(currentVolumePath, disk.toString(), domainBlockCopyParameters.getTypedParameters(), 0);
} else {
throw new LibvirtException("Couldn't find disk: " + command.getVolumePath() + " on vm: " + dm.getName());
}
logger.debug("Waiting for block copy for domain " + dm.getName() + " from " + currentVolumePath + " to " + newVolumePath + " to finish");
completeSignal.await();
logger.debug("Refreshing storage pool " + command.getPool().getUuid());
final StoragePool storagePool = conn.storagePoolLookupByUUIDString(command.getPool().getUuid());
storagePool.refresh(0);
isMigrationSuccessfull = true;
} catch (final LibvirtException | InterruptedException e) {
logger.debug("Can't migrate disk: " + e.getMessage());
result = e.getMessage();
} finally {
try {
if (dm != null) {
dm.free();
}
// Stop block job listener
if (conn != null) {
conn.removeBlockJobListener(blockJobListener);
}
} catch (final LibvirtException e) {
logger.debug("Ignoring libvirt error.", e);
}
}
try {
if (isMigrationSuccessfull && conn != null) {
logger.debug("Cleaning up old disk " + currentVolumePath);
final StorageVol storageVol = conn.storageVolLookupByPath(currentVolumePath);
storageVol.delete(0);
}
} catch (final LibvirtException e) {
logger.error("Cleaning up old disk " + currentVolumePath + " failed!", e);
}
return new MigrateVolumeAnswer(command, result == null, result, command.getVolumePath());
}
use of com.cloud.agent.resource.kvm.xml.LibvirtDiskDef in project cosmic by MissionCriticalCloud.
the class LibvirtMigrateCommandWrapper method execute.
@Override
public Answer execute(final MigrateCommand command, final LibvirtComputingResource libvirtComputingResource) {
final String vmName = command.getVmName();
String result = null;
List<LibvirtVmDef.InterfaceDef> ifaces = null;
final List<LibvirtDiskDef> disks;
Domain dm = null;
Connect dconn = null;
Domain destDomain = null;
Connect conn = null;
final String xmlDesc;
List<Ternary<String, Boolean, String>> vmsnapshots = null;
try {
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper();
conn = libvirtUtilitiesHelper.getConnectionByVmName(vmName);
ifaces = libvirtComputingResource.getInterfaces(conn, vmName);
disks = libvirtComputingResource.getDisks(conn, vmName);
dm = conn.domainLookupByName(vmName);
/*
* We replace the private IP address with the address of the destination host. This is because the VNC listens on
* the private IP address of the hypervisor, but that address is ofcourse different on the target host.
*
* MigrateCommand.getDestinationIp() returns the private IP address of the target hypervisor. So it's safe to use.
*
* The Domain.migrate method from libvirt supports passing a different XML description for the instance to be used
* on the target host.
*
* This is supported by libvirt-java from version 0.50.0
*
* CVE-2015-3252: Get XML with sensitive information suitable for migration by using VIR_DOMAIN_XML_MIGRATABLE
* flag (value = 8) https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainXMLFlags
*
* Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
*/
// 1000000 equals v1.0.0
final int xmlFlag = conn.getLibVirVersion() >= 1000000 ? 8 : 1;
xmlDesc = dm.getXMLDesc(xmlFlag).replace(libvirtComputingResource.getPrivateIp(), command.getDestinationIp());
// delete the metadata of vm snapshots before migration
vmsnapshots = libvirtComputingResource.cleanVMSnapshotMetadata(dm);
dconn = libvirtUtilitiesHelper.retrieveQemuConnection("qemu+tcp://" + command.getDestinationIp() + "/system");
// run migration in thread so we can monitor it
s_logger.info("Live migration of instance " + vmName + " initiated");
final ExecutorService executor = Executors.newFixedThreadPool(1);
final Callable<Domain> worker = new MigrateKvmAsync(libvirtComputingResource, dm, dconn, xmlDesc, vmName, command.getDestinationIp());
final Future<Domain> migrateThread = executor.submit(worker);
executor.shutdown();
long sleeptime = 0;
while (!executor.isTerminated()) {
Thread.sleep(100);
sleeptime += 100;
if (sleeptime == 1000) {
final int migrateDowntime = libvirtComputingResource.getMigrateDowntime();
if (migrateDowntime > 0) {
try {
final int setDowntime = dm.migrateSetMaxDowntime(migrateDowntime);
if (setDowntime == 0) {
s_logger.debug("Set max downtime for migration of " + vmName + " to " + String.valueOf(migrateDowntime) + "ms");
}
} catch (final LibvirtException e) {
s_logger.debug("Failed to set max downtime for migration, perhaps migration completed? Error: " + e.getMessage());
}
}
}
if (sleeptime % 1000 == 0) {
s_logger.info("Waiting for migration of " + vmName + " to complete, waited " + sleeptime + "ms");
}
// pause vm if we meet the vm.migrate.pauseafter threshold and not already paused
final int migratePauseAfter = libvirtComputingResource.getMigratePauseAfter();
if (migratePauseAfter > 0 && sleeptime > migratePauseAfter) {
DomainState state = null;
try {
state = dm.getInfo().state;
} catch (final LibvirtException e) {
s_logger.info("Couldn't get VM domain state after " + sleeptime + "ms: " + e.getMessage());
}
if (state != null && state == DomainState.VIR_DOMAIN_RUNNING) {
try {
s_logger.info("Pausing VM " + vmName + " due to property vm.migrate.pauseafter setting to " + migratePauseAfter + "ms to complete migration");
dm.suspend();
} catch (final LibvirtException e) {
// pause could be racy if it attempts to pause right when vm is finished, simply warn
s_logger.info("Failed to pause vm " + vmName + " : " + e.getMessage());
}
}
}
}
s_logger.info("Migration thread for " + vmName + " is done");
destDomain = migrateThread.get(10, TimeUnit.SECONDS);
if (destDomain != null) {
for (final LibvirtDiskDef disk : disks) {
libvirtComputingResource.cleanupDisk(disk);
}
}
} catch (final LibvirtException e) {
s_logger.debug("Can't migrate domain: " + e.getMessage());
result = e.getMessage();
} catch (final InterruptedException e) {
s_logger.debug("Interrupted while migrating domain: " + e.getMessage());
result = e.getMessage();
} catch (final ExecutionException e) {
s_logger.debug("Failed to execute while migrating domain: " + e.getMessage());
result = e.getMessage();
} catch (final TimeoutException e) {
s_logger.debug("Timed out while migrating domain: " + e.getMessage());
result = e.getMessage();
} finally {
try {
if (dm != null && result != null) {
// restore vm snapshots in case of failed migration
if (vmsnapshots != null) {
libvirtComputingResource.restoreVMSnapshotMetadata(dm, vmName, vmsnapshots);
}
}
if (dm != null) {
if (dm.isPersistent() == 1) {
dm.undefine();
}
dm.free();
}
if (dconn != null) {
dconn.close();
}
if (destDomain != null) {
destDomain.free();
}
} catch (final LibvirtException e) {
s_logger.trace("Ignoring libvirt error.", e);
}
}
if (result == null) {
for (final LibvirtVmDef.InterfaceDef iface : ifaces) {
// We don't know which "traffic type" is associated with
// each interface at this point, so inform all vif drivers
final List<VifDriver> allVifDrivers = libvirtComputingResource.getAllVifDrivers();
for (final VifDriver vifDriver : allVifDrivers) {
vifDriver.unplug(iface);
}
}
}
return new MigrateAnswer(command, result == null, result, null);
}
Aggregations