use of org.libvirt.DomainInfo.DomainState in project cosmic by MissionCriticalCloud.
the class LibvirtBackupSnapshotCommandWrapper method execute.
@Override
public Answer execute(final BackupSnapshotCommand command, final LibvirtComputingResource libvirtComputingResource) {
final Long dcId = command.getDataCenterId();
final Long accountId = command.getAccountId();
final Long volumeId = command.getVolumeId();
final String secondaryStoragePoolUrl = command.getSecondaryStorageUrl();
final String snapshotName = command.getSnapshotName();
String snapshotDestPath = null;
String snapshotRelPath = null;
final String vmName = command.getVmName();
KvmStoragePool secondaryStoragePool = null;
final KvmStoragePoolManager storagePoolMgr = libvirtComputingResource.getStoragePoolMgr();
try {
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper();
final Connect conn = libvirtUtilitiesHelper.getConnectionByVmName(vmName);
secondaryStoragePool = storagePoolMgr.getStoragePoolByUri(secondaryStoragePoolUrl);
final String ssPmountPath = secondaryStoragePool.getLocalPath();
snapshotRelPath = File.separator + "snapshots" + File.separator + dcId + File.separator + accountId + File.separator + volumeId;
snapshotDestPath = ssPmountPath + File.separator + "snapshots" + File.separator + dcId + File.separator + accountId + File.separator + volumeId;
final KvmStoragePool primaryPool = storagePoolMgr.getStoragePool(command.getPool().getType(), command.getPrimaryStoragePoolNameLabel());
final KvmPhysicalDisk snapshotDisk = primaryPool.getPhysicalDisk(command.getVolumePath());
final String manageSnapshotPath = libvirtComputingResource.manageSnapshotPath();
final int cmdsTimeout = libvirtComputingResource.getCmdsTimeout();
if (primaryPool.getType() == StoragePoolType.RBD) {
try {
final Rados r = new Rados(primaryPool.getAuthUserName());
r.confSet("mon_host", primaryPool.getSourceHost() + ":" + primaryPool.getSourcePort());
r.confSet("key", primaryPool.getAuthSecret());
r.confSet("client_mount_timeout", "30");
r.connect();
s_logger.debug("Succesfully connected to Ceph cluster at " + r.confGet("mon_host"));
final IoCTX io = r.ioCtxCreate(primaryPool.getSourceDir());
final Rbd rbd = new Rbd(io);
final RbdImage image = rbd.open(snapshotDisk.getName(), snapshotName);
final File fh = new File(snapshotDestPath);
try (final BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(fh))) {
final int chunkSize = 4194304;
long offset = 0;
s_logger.debug("Backuping up RBD snapshot " + snapshotName + " to " + snapshotDestPath);
while (true) {
final byte[] buf = new byte[chunkSize];
final int bytes = image.read(offset, buf, chunkSize);
if (bytes <= 0) {
break;
}
bos.write(buf, 0, bytes);
offset += bytes;
}
s_logger.debug("Completed backing up RBD snapshot " + snapshotName + " to " + snapshotDestPath + ". Bytes written: " + offset);
} catch (final IOException ex) {
s_logger.error("BackupSnapshotAnswer:Exception:" + ex.getMessage());
}
r.ioCtxDestroy(io);
} catch (final RadosException e) {
s_logger.error("A RADOS operation failed. The error was: " + e.getMessage());
return new BackupSnapshotAnswer(command, false, e.toString(), null, true);
} catch (final RbdException e) {
s_logger.error("A RBD operation on " + snapshotDisk.getName() + " failed. The error was: " + e.getMessage());
return new BackupSnapshotAnswer(command, false, e.toString(), null, true);
}
} else {
final Script scriptCommand = new Script(manageSnapshotPath, cmdsTimeout, s_logger);
scriptCommand.add("-b", snapshotDisk.getPath());
scriptCommand.add("-n", snapshotName);
scriptCommand.add("-p", snapshotDestPath);
scriptCommand.add("-t", snapshotName);
final String result = scriptCommand.execute();
if (result != null) {
s_logger.debug("Failed to backup snaptshot: " + result);
return new BackupSnapshotAnswer(command, false, result, null, true);
}
}
/* Delete the snapshot on primary */
DomainState state = null;
Domain vm = null;
if (vmName != null) {
try {
vm = libvirtComputingResource.getDomain(conn, command.getVmName());
state = vm.getInfo().state;
} catch (final LibvirtException e) {
s_logger.trace("Ignoring libvirt error.", e);
}
}
final KvmStoragePool primaryStorage = storagePoolMgr.getStoragePool(command.getPool().getType(), command.getPool().getUuid());
if (state == DomainState.VIR_DOMAIN_RUNNING && !primaryStorage.isExternalSnapshot()) {
final MessageFormat snapshotXml = new MessageFormat(" <domainsnapshot>" + " <name>{0}</name>" + " <domain>" + " <uuid>{1}</uuid>" + " </domain>" + " </domainsnapshot>");
final String vmUuid = vm.getUUIDString();
final Object[] args = new Object[] { snapshotName, vmUuid };
final String snapshot = snapshotXml.format(args);
s_logger.debug(snapshot);
final DomainSnapshot snap = vm.snapshotLookupByName(snapshotName);
if (snap != null) {
snap.delete(0);
} else {
throw new CloudRuntimeException("Unable to find vm snapshot with name -" + snapshotName);
}
/*
* libvirt on RHEL6 doesn't handle resume event emitted from qemu
*/
vm = libvirtComputingResource.getDomain(conn, command.getVmName());
state = vm.getInfo().state;
if (state == DomainState.VIR_DOMAIN_PAUSED) {
vm.resume();
}
} else {
final Script scriptCommand = new Script(manageSnapshotPath, cmdsTimeout, s_logger);
scriptCommand.add("-d", snapshotDisk.getPath());
scriptCommand.add("-n", snapshotName);
final String result = scriptCommand.execute();
if (result != null) {
s_logger.debug("Failed to backup snapshot: " + result);
return new BackupSnapshotAnswer(command, false, "Failed to backup snapshot: " + result, null, true);
}
}
} catch (final LibvirtException e) {
return new BackupSnapshotAnswer(command, false, e.toString(), null, true);
} catch (final CloudRuntimeException e) {
return new BackupSnapshotAnswer(command, false, e.toString(), null, true);
} finally {
if (secondaryStoragePool != null) {
storagePoolMgr.deleteStoragePool(secondaryStoragePool.getType(), secondaryStoragePool.getUuid());
}
}
return new BackupSnapshotAnswer(command, true, null, snapshotRelPath + File.separator + snapshotName, true);
}
use of org.libvirt.DomainInfo.DomainState in project cosmic by MissionCriticalCloud.
the class LibvirtCreateVMSnapshotCommandWrapper method execute.
@Override
public Answer execute(final CreateVMSnapshotCommand cmd, final LibvirtComputingResource libvirtComputingResource) {
final String vmName = cmd.getVmName();
final String vmSnapshotName = cmd.getTarget().getSnapshotName();
Domain dm = null;
try {
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper();
final Connect conn = libvirtUtilitiesHelper.getConnection();
dm = libvirtComputingResource.getDomain(conn, vmName);
if (dm == null) {
return new CreateVMSnapshotAnswer(cmd, false, "Create VM Snapshot Failed due to can not find vm: " + vmName);
}
final DomainState domainState = dm.getInfo().state;
if (domainState != DomainState.VIR_DOMAIN_RUNNING) {
return new CreateVMSnapshotAnswer(cmd, false, "Create VM Snapshot Failed due to vm is not running: " + vmName + " with domainState = " + domainState);
}
final String vmSnapshotXML = "<domainsnapshot><name>" + vmSnapshotName + "</name><memory snapshot='internal' /></domainsnapshot>";
dm.snapshotCreateXML(vmSnapshotXML);
return new CreateVMSnapshotAnswer(cmd, cmd.getTarget(), cmd.getVolumeTOs());
} catch (final LibvirtException e) {
final String msg = " Create VM snapshot failed due to " + e.toString();
s_logger.warn(msg, e);
return new CreateVMSnapshotAnswer(cmd, false, msg);
} finally {
if (dm != null) {
try {
dm.free();
} catch (final LibvirtException l) {
s_logger.trace("Ignoring libvirt error.", l);
}
}
}
}
use of org.libvirt.DomainInfo.DomainState 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