protected void assertThatTheRightLibvirtApiIsInvokedForRunInstance() throws Exception { int[] domains = stubLibvirtConnection.listDomains(); assertEquals(1, domains.length); Domain domain = stubLibvirtConnection.domainLookupByID(domains[0]); assertEquals(domain.getName(), instanceId); String domainXml = domain.getXMLDesc(0); assertThatDomainXmlContainsNecessaryFields(domainXml); }
@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(); /** * RBD snapshots can't be copied using qemu-img, so we have to use the Java bindings for * librbd here. * * <p>These bindings will read the snapshot and write the contents to the secondary storage * directly * * <p>It will stop doing so if the amount of time spend is longer then cmds.timeout */ 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 (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); }