diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java b/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java index a93bf4adfa3..ed812b18f89 100644 --- a/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java +++ b/agent/src/com/cloud/agent/resource/computing/LibvirtComputingResource.java @@ -82,6 +82,9 @@ import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand; import com.cloud.agent.api.CreateStoragePoolCommand; import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer; import com.cloud.agent.api.CreateVolumeFromSnapshotCommand; +import com.cloud.agent.api.DeleteSnapshotBackupAnswer; +import com.cloud.agent.api.DeleteSnapshotBackupCommand; +import com.cloud.agent.api.DeleteSnapshotsDirCommand; import com.cloud.agent.api.DeleteStoragePoolCommand; import com.cloud.agent.api.FenceAnswer; import com.cloud.agent.api.FenceCommand; @@ -164,6 +167,10 @@ import com.cloud.agent.resource.computing.LibvirtVMDef.InterfaceDef.hostNicType; import com.cloud.agent.resource.computing.LibvirtVMDef.SerialDef; import com.cloud.agent.resource.computing.LibvirtVMDef.TermPolicy; import com.cloud.agent.resource.virtualnetwork.VirtualRoutingResource; +import com.cloud.agent.storage.KVMPhysicalDisk; +import com.cloud.agent.storage.KVMStoragePool; +import com.cloud.agent.storage.KVMStoragePoolManager; +import com.cloud.agent.storage.LibvirtStorageAdaptor; import com.cloud.dc.Vlan; import com.cloud.exception.InternalErrorException; import com.cloud.host.Host.Type; @@ -175,6 +182,7 @@ import com.cloud.resource.ServerResource; import com.cloud.resource.ServerResourceBase; import com.cloud.storage.Storage; import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StorageLayer; import com.cloud.storage.Volume; import com.cloud.storage.template.Processor; @@ -239,6 +247,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv private final String _SSHPUBKEYPATH = _SSHKEYSPATH + File.separator + "id_rsa.pub.cloud"; private String _mountPoint = "/mnt"; StorageLayer _storage; + private KVMStoragePoolManager _storagePoolMgr; private static final class KeyValueInterpreter extends OutputInterpreter { private final Map map = new HashMap(); @@ -318,7 +327,6 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv protected List _vmsKilled = new ArrayList(); private VirtualRoutingResource _virtRouterResource; - protected LibvirtStorageResource _storageResource; private String _pingTestPath; @@ -416,6 +424,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv return false; } + + try { Class clazz = Class.forName("com.cloud.storage.JavaStorageLayer"); _storage = (StorageLayer)ComponentLocator.inject(clazz); @@ -423,6 +433,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv } catch (ClassNotFoundException e) { throw new ConfigurationException("Unable to find class " + "com.cloud.storage.JavaStorageLayer"); } + + _storagePoolMgr = new KVMStoragePoolManager(_storage); _virtRouterResource = new VirtualRoutingResource(); @@ -680,8 +692,6 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv if (_mountPoint == null) { _mountPoint = "/mnt"; } - - _storageResource = new LibvirtStorageResource(this, _storage, _createvmPath, _timeout, _mountPoint, _monitor); saveProperties(params); @@ -932,47 +942,33 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv String volumePath = cmd.getVolumePath(); StorageFilerTO pool = cmd.getPool(); String secondaryStorageUrl = cmd.getSecondaryStorageURL(); - StoragePool primaryPool = null; - Connect conn; - try { - conn = LibvirtConnection.getConnection(); - primaryPool = _storageResource.getStoragePool(conn, pool.getUuid()); - LibvirtStoragePoolDef primary = _storageResource.getStoragePoolDef(conn, primaryPool); - String primaryMountPath = primary.getTargetPath(); - - StoragePool secondaryStoragePool = _storageResource.getStoragePoolbyURI(conn, new URI(secondaryStorageUrl)); - LibvirtStoragePoolDef spd = _storageResource.getStoragePoolDef(conn, secondaryStoragePool); - String ssPmountPath = spd.getTargetPath(); - - String volumeName = UUID.randomUUID().toString(); - - if (copyToSecondary) { - StorageVol volume = _storageResource.getVolume(conn, primaryPool, volumePath); - String volumeDestPath = ssPmountPath + File.separator + "volumes/" + cmd.getVolumeId() + File.separator; - _storageResource.copyVolume(volumePath, volumeDestPath, volumeName, _cmdsTimeout); - return new CopyVolumeAnswer(cmd, true, null, null, volumeName); - } else { - volumePath = ssPmountPath + File.separator + "volumes/" + cmd.getVolumeId() + File.separator + volumePath; - _storageResource.copyVolume(volumePath, primaryMountPath, volumeName, _cmdsTimeout); - return new CopyVolumeAnswer(cmd, true, null, null, primaryMountPath + File.separator + volumeName); - } - - } catch (LibvirtException e) { - return new CopyVolumeAnswer(cmd, false, e.toString(), null, null); - } catch (URISyntaxException e) { - return new CopyVolumeAnswer(cmd, false, e.toString(), null, null); - } catch (InternalErrorException e) { - return new CopyVolumeAnswer(cmd, false, e.toString(), null, null); - } - - } + try { + KVMStoragePool primaryPool = _storagePoolMgr.getStoragePool(pool.getUuid()); + String volumeName = UUID.randomUUID().toString(); + + if (copyToSecondary) { + KVMPhysicalDisk volume = primaryPool.getPhysicalDisk(cmd.getVolumePath()); + String volumeDestPath = "/volumes/" + cmd.getVolumeId() + File.separator; + KVMStoragePool secondaryStoragePool = _storagePoolMgr.getStoragePoolByURI(secondaryStorageUrl + volumeDestPath); + _storagePoolMgr.copyPhysicalDisk(volume, volumeName, secondaryStoragePool); + return new CopyVolumeAnswer(cmd, true, null, null, volumeName); + } else { + volumePath = "/volumes/" + cmd.getVolumeId() + File.separator + volumePath; + KVMStoragePool secondaryStoragePool = _storagePoolMgr.getStoragePoolByURI(secondaryStorageUrl + volumePath); + KVMPhysicalDisk volume = secondaryStoragePool.getPhysicalDisk(cmd.getVolumePath()); + _storagePoolMgr.copyPhysicalDisk(volume, volumeName, primaryPool); + return new CopyVolumeAnswer(cmd, true, null, null, volumeName); + } + } catch (CloudRuntimeException e) { + return new CopyVolumeAnswer(cmd, false, e.toString(), null, null); + } + } protected Answer execute(DeleteStoragePoolCommand cmd) { try { - Connect conn = LibvirtConnection.getConnection(); - _storageResource.deleteStoragePool(conn, cmd.getPool()); + _storagePoolMgr.deleteStoragePool(cmd.getPool().getUuid()); return new Answer(cmd); - } catch (LibvirtException e) { + } catch (CloudRuntimeException e) { return new Answer(cmd, false, e.toString()); } } @@ -1006,48 +1002,32 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv protected Answer execute(CreateCommand cmd) { StorageFilerTO pool = cmd.getPool(); DiskProfile dskch = cmd.getDiskCharacteristics(); - StorageVol tmplVol = null; - StoragePool primaryPool = null; - StorageVol vol = null; + KVMPhysicalDisk BaseVol = null; + KVMStoragePool primaryPool = null; + KVMPhysicalDisk vol = null; long disksize; try { - Connect conn = LibvirtConnection.getConnection(); - primaryPool = _storageResource.getStoragePool(conn, pool.getUuid()); + primaryPool = _storagePoolMgr.getStoragePool(pool.getUuid()); if (cmd.getTemplateUrl() != null) { - tmplVol = _storageResource.getVolume(conn, primaryPool, cmd.getTemplateUrl()); - - vol = _storageResource.createVolumeFromTempl(primaryPool, tmplVol); + + BaseVol = primaryPool.getPhysicalDisk(cmd.getTemplateUrl()); + vol = _storagePoolMgr.createDiskFromTemplate(BaseVol, UUID.randomUUID().toString(), primaryPool); if (vol == null) { return new Answer(cmd, false, " Can't create storage volume on storage pool"); } - disksize = tmplVol.getInfo().capacity; + disksize = vol.getSize(); } else { disksize = dskch.getSize(); - vol = _storageResource.createVolume(conn, primaryPool, UUID.randomUUID().toString(), dskch.getSize(), volFormat.QCOW2); + vol = primaryPool.createPhysicalDisk(UUID.randomUUID().toString(), dskch.getSize()); } VolumeTO volume = new VolumeTO(cmd.getVolumeId(), dskch.getType(), pool.getType(), pool.getUuid(), - pool.getPath(), vol.getName(), vol.getKey(),disksize, null); + pool.getPath(), vol.getName(), vol.getName(), disksize, null); return new CreateAnswer(cmd, volume); - } catch (LibvirtException e) { - + } catch (CloudRuntimeException e) { s_logger.debug("Failed to create volume: " + e.toString()); return new CreateAnswer(cmd, e); - } finally { - try { - if (vol != null) { - vol.free(); - } - if (tmplVol != null) { - tmplVol.free(); - } - if (primaryPool != null) { - primaryPool.free(); - } - } catch (LibvirtException e) { - - } } } @@ -1055,13 +1035,11 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv VolumeTO vol = cmd.getVolume(); try { - Connect conn = LibvirtConnection.getConnection(); - StoragePool pool = _storageResource.getStoragePool(conn, vol.getPoolUuid()); - StorageVol volume = _storageResource.getVolume(conn, pool, vol.getPath()); - volume.delete(0); - volume.free(); + KVMStoragePool pool = _storagePoolMgr.getStoragePool(vol.getPoolUuid()); + pool.deletePhysicalDisk(vol.getName()); + return new Answer(cmd, true, "Success"); - } catch (LibvirtException e) { + } catch (CloudRuntimeException e) { s_logger.debug("Failed to delete volume: " + e.toString()); return new Answer(cmd, false, e.toString()); } @@ -1171,7 +1149,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv } } - if (state == DomainInfo.DomainState.VIR_DOMAIN_RUNNING) { + KVMStoragePool primaryPool = _storagePoolMgr.getStoragePool(cmd.getPool().getUuid()); + if (state == DomainInfo.DomainState.VIR_DOMAIN_RUNNING && !primaryPool.isExternalSnapshot()) { String vmUuid = vm.getUUIDString(); Object[] args = new Object[] {snapshotName, vmUuid}; String snapshot = SnapshotXML.format(args); @@ -1220,13 +1199,17 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv String snapshotName = cmd.getSnapshotName(); String snapshotPath = cmd.getVolumePath(); String snapshotDestPath = null; + String snapshotRelPath = null; String vmName = cmd.getVmName(); try { Connect conn = LibvirtConnection.getConnection(); - StoragePool secondaryStoragePool = _storageResource.getStoragePoolbyURI(conn, new URI(secondaryStoragePoolUrl)); - LibvirtStoragePoolDef spd = _storageResource.getStoragePoolDef(conn, secondaryStoragePool); - String ssPmountPath = spd.getTargetPath(); + + KVMStoragePool secondaryStoragePool = _storagePoolMgr.getStoragePoolByURI(secondaryStoragePoolUrl); + + 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; Script command = new Script(_manageSnapshotPath, _cmdsTimeout, s_logger); command.add("-b", snapshotPath); @@ -1251,7 +1234,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv } } - if (state == DomainInfo.DomainState.VIR_DOMAIN_RUNNING) { + KVMStoragePool primaryStorage = _storagePoolMgr.getStoragePool(cmd.getPool().getUuid()); + if (state == DomainInfo.DomainState.VIR_DOMAIN_RUNNING && !primaryStorage.isExternalSnapshot()) { String vmUuid = vm.getUUIDString(); Object[] args = new Object[] {snapshotName, vmUuid}; String snapshot = SnapshotXML.format(args); @@ -1277,38 +1261,73 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv } } catch (LibvirtException e) { return new BackupSnapshotAnswer(cmd, false, e.toString(), null, true); - } catch (URISyntaxException e) { + } catch (CloudRuntimeException e) { return new BackupSnapshotAnswer(cmd, false, e.toString(), null, true); } - return new BackupSnapshotAnswer(cmd, true, null, snapshotDestPath + File.separator + snapshotName, true); + return new BackupSnapshotAnswer(cmd, true, null, snapshotRelPath + File.separator + snapshotName, true); } + + + + protected DeleteSnapshotBackupAnswer execute(final DeleteSnapshotBackupCommand cmd) { + Long dcId = cmd.getDataCenterId(); + Long accountId = cmd.getAccountId(); + Long volumeId = cmd.getVolumeId(); + try { + KVMStoragePool secondaryStoragePool = _storagePoolMgr.getStoragePoolByURI(cmd.getSecondaryStorageUrl()); + + String ssPmountPath = secondaryStoragePool.getLocalPath(); + String snapshotDestPath = ssPmountPath + File.separator + "snapshots" + File.separator + dcId + File.separator + accountId + File.separator + volumeId; + + final Script command = new Script(_manageSnapshotPath, _cmdsTimeout, s_logger); + command.add("-d", snapshotDestPath); + command.add("-n", cmd.getSnapshotName()); + + command.execute(); + } catch (CloudRuntimeException e) { + return new DeleteSnapshotBackupAnswer(cmd, false, e.toString()); + } + return new DeleteSnapshotBackupAnswer(cmd, true, null); + } + + protected Answer execute(DeleteSnapshotsDirCommand cmd) { + Long dcId = cmd.getDcId(); + Long accountId = cmd.getAccountId(); + Long volumeId = cmd.getVolumeId(); + try { + KVMStoragePool secondaryStoragePool = _storagePoolMgr.getStoragePoolByURI(cmd.getSecondaryStorageUrl()); + + String ssPmountPath = secondaryStoragePool.getLocalPath(); + String snapshotDestPath = ssPmountPath + File.separator + "snapshots" + File.separator + dcId + File.separator + accountId + File.separator + volumeId; + + final Script command = new Script(_manageSnapshotPath, _cmdsTimeout, s_logger); + command.add("-d", snapshotDestPath); + command.add("-f"); + command.execute(); + } catch (CloudRuntimeException e) { + return new Answer(cmd, false, e.toString()); + } + return new Answer(cmd, true, null); + } protected CreateVolumeFromSnapshotAnswer execute(final CreateVolumeFromSnapshotCommand cmd) { try { - Connect conn = LibvirtConnection.getConnection(); - /*Make sure secondary storage is mounted*/ - _storageResource.getStoragePoolbyURI(conn, new URI(cmd.getSecondaryStorageUrl())); String snapshotPath = cmd.getSnapshotUuid(); - String primaryUuid = cmd.getPrimaryStoragePoolNameLabel(); - StoragePool primaryPool = _storageResource.getStoragePool(conn, primaryUuid); - LibvirtStoragePoolDef spd = _storageResource.getStoragePoolDef(conn, primaryPool); - String primaryPath = spd.getTargetPath(); - String volUuid = UUID.randomUUID().toString(); - String volPath = primaryPath + File.separator + volUuid; - String result = executeBashScript("cp " + snapshotPath + " " + volPath); - if (result != null) { - return new CreateVolumeFromSnapshotAnswer(cmd, false, result, null); - } - return new CreateVolumeFromSnapshotAnswer(cmd, true, "", volPath); - } catch (LibvirtException e) { - return new CreateVolumeFromSnapshotAnswer(cmd, false, e.toString(), null); - } catch (URISyntaxException e) { - return new CreateVolumeFromSnapshotAnswer(cmd, false, e.toString(), null); - } finally { + int index = snapshotPath.lastIndexOf("/"); + snapshotPath = snapshotPath.substring(0, index); + KVMStoragePool secondaryPool = _storagePoolMgr.getStoragePoolByURI(cmd.getSecondaryStorageUrl() + snapshotPath); + KVMPhysicalDisk snapshot = secondaryPool.getPhysicalDisk(cmd.getSnapshotName()); - } + String primaryUuid = cmd.getPrimaryStoragePoolNameLabel(); + KVMStoragePool primaryPool = _storagePoolMgr.getStoragePool(primaryUuid); + String volUuid = UUID.randomUUID().toString(); + KVMPhysicalDisk disk = _storagePoolMgr.createDiskFromSnapshot(snapshot, cmd.getSnapshotName(), volUuid, primaryPool); + return new CreateVolumeFromSnapshotAnswer(cmd, true, "", disk.getPath()); + } catch (CloudRuntimeException e) { + return new CreateVolumeFromSnapshotAnswer(cmd, false, e.toString(), null); + } } @@ -1323,12 +1342,14 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv String snapshotPath = cmd.getSnapshotUuid(); String tmplName = UUID.randomUUID().toString(); String tmplFileName = tmplName + ".qcow2"; - StoragePool secondaryPool; + KVMStoragePool secondaryPool; try { - Connect conn = LibvirtConnection.getConnection(); - secondaryPool = _storageResource.getStoragePoolbyURI(conn, new URI(cmd.getSecondaryStorageUrl())); - LibvirtStoragePoolDef spd = _storageResource.getStoragePoolDef(conn, secondaryPool); - String templatePath = spd.getTargetPath() + File.separator + templateInstallFolder; + + + secondaryPool = _storagePoolMgr.getStoragePoolByURI(cmd.getSecondaryStorageUrl()); + + String templatePath = secondaryPool.getLocalPath() + File.separator + templateInstallFolder; + _storage.mkdirs(templatePath); String tmplPath = templateInstallFolder + File.separator + tmplFileName; @@ -1350,47 +1371,23 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv loc.save(); return new CreatePrivateTemplateAnswer(cmd, true, "", tmplPath, info.virtualSize, info.size, tmplName, info.format); - } catch (LibvirtException e) { - return new CreatePrivateTemplateAnswer(cmd, false, e.getMessage()); - } catch (URISyntaxException e) { - return new CreatePrivateTemplateAnswer(cmd, false, e.getMessage()); } catch (ConfigurationException e) { return new CreatePrivateTemplateAnswer(cmd, false, e.getMessage()); } catch (InternalErrorException e) { return new CreatePrivateTemplateAnswer(cmd, false, e.getMessage()); } catch (IOException e) { return new CreatePrivateTemplateAnswer(cmd, false, e.getMessage()); - } + } catch (CloudRuntimeException e) { + return new CreatePrivateTemplateAnswer(cmd, false, e.getMessage()); + } } protected GetStorageStatsAnswer execute(final GetStorageStatsCommand cmd) { - StoragePool sp = null; try { - Connect conn = LibvirtConnection.getConnection(); - sp = _storageResource.getStoragePool(conn, cmd.getStorageId()); - LibvirtStoragePoolDef spd = _storageResource.getStoragePoolDef(conn, sp); - String mountPoint = spd.getTargetPath(); - - Script statsScript = new Script("/bin/bash", s_logger); - statsScript.add("-c"); - statsScript.add("stats=$(df --total " + mountPoint + " |grep total|awk '{print $2,$3}');echo $stats"); - final OutputInterpreter.OneLineParser statsParser = new OutputInterpreter.OneLineParser(); - String result = statsScript.execute(statsParser); - if (result != null) { - return new GetStorageStatsAnswer(cmd, result); - } - String stats = statsParser.getLine(); - if (stats != null && !stats.isEmpty()) { - String sizes[] = stats.trim().split(" "); - if (sizes.length != 2) { - return new GetStorageStatsAnswer(cmd, "Failed to parse the result: " + stats); - } - return new GetStorageStatsAnswer(cmd, Long.parseLong(sizes[0]) * 1024, Long.parseLong(sizes[1]) * 1024); - } else { - return new GetStorageStatsAnswer(cmd, "Failed to parse result from df"); - } - } catch (LibvirtException e) { + KVMStoragePool sp = _storagePoolMgr.getStoragePool(cmd.getStorageId()); + return new GetStorageStatsAnswer(cmd, sp.getCapacity(), sp.getUsed()); + } catch (CloudRuntimeException e) { return new GetStorageStatsAnswer(cmd, e.toString()); } } @@ -1398,18 +1395,18 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv protected CreatePrivateTemplateAnswer execute(CreatePrivateTemplateFromVolumeCommand cmd) { String secondaryStorageURL = cmd.getSecondaryStorageUrl(); - StoragePool secondaryStorage = null; + KVMStoragePool secondaryStorage = null; try { Connect conn = LibvirtConnection.getConnection(); String templateFolder = cmd.getAccountId() + File.separator + cmd.getTemplateId() + File.separator; String templateInstallFolder = "/template/tmpl/" + templateFolder; - secondaryStorage = _storageResource.getStoragePoolbyURI(conn, new URI(secondaryStorageURL)); + secondaryStorage = _storagePoolMgr.getStoragePoolByURI(secondaryStorageURL); - LibvirtStoragePoolDef spd = _storageResource.getStoragePoolDef(conn, secondaryStorage); - String tmpltPath = spd.getTargetPath() + File.separator + templateInstallFolder; + + String tmpltPath = secondaryStorage.getLocalPath() + File.separator + templateInstallFolder; _storage.mkdirs(tmpltPath); - + Script command = new Script(_createTmplPath, _timeout, s_logger); command.add("-f", cmd.getVolumePath()); command.add("-t", tmpltPath); @@ -1443,8 +1440,6 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv info.size, cmd.getUniqueName(), ImageFormat.QCOW2); - } catch (URISyntaxException e) { - return new CreatePrivateTemplateAnswer(cmd, false, e.toString()); } catch (LibvirtException e) { s_logger.debug("Failed to get secondary storage pool: " + e.toString()); return new CreatePrivateTemplateAnswer(cmd, false, e.toString()); @@ -1452,9 +1447,10 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv return new CreatePrivateTemplateAnswer(cmd, false, e.toString()); } catch (IOException e) { return new CreatePrivateTemplateAnswer(cmd, false, e.toString()); - } catch (ConfigurationException e) { return new CreatePrivateTemplateAnswer(cmd, false, e.toString()); + } catch (CloudRuntimeException e) { + return new CreatePrivateTemplateAnswer(cmd, false, e.toString()); } } @@ -1467,70 +1463,38 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv tmpltname = tmplturl.substring(index + 1); } - StoragePool secondaryPool = null; - StoragePool primaryPool = null; - StorageVol tmplVol = null; - StorageVol primaryVol = null; - Connect conn = null; + KVMPhysicalDisk tmplVol = null; + try { - conn = LibvirtConnection.getConnection(); - secondaryPool = _storageResource.getStoragePoolbyURI(conn, new URI(mountpoint)); + KVMStoragePool secondaryPool = _storagePoolMgr.getStoragePoolByURI(mountpoint); /*Get template vol*/ if (tmpltname == null) { - /*Hack: server just pass the directory of system vm template, need to scan the folder */ - _storageResource.storagePoolRefresh(secondaryPool); - String[] volumes = secondaryPool.listVolumes(); - if (volumes == null) { - return new PrimaryStorageDownloadAnswer("Failed to get volumes from pool: " + secondaryPool.getName()); + secondaryPool.refresh(); + List disks = secondaryPool.listPhysicalDisks(); + if (disks == null || disks.isEmpty()) { + return new PrimaryStorageDownloadAnswer("Failed to get volumes from pool: " + secondaryPool.getUuid()); } - for (String volumeName : volumes) { - if (volumeName.endsWith("qcow2")) { - tmpltname = volumeName; + for (KVMPhysicalDisk disk : disks) { + if (disk.getName().endsWith("qcow2")) { + tmplVol = disk; break; } } - if (tmpltname == null) { - return new PrimaryStorageDownloadAnswer("Failed to get template from pool: " + secondaryPool.getName()); + if (tmplVol == null) { + return new PrimaryStorageDownloadAnswer("Failed to get template from pool: " + secondaryPool.getUuid()); } } - LibvirtStoragePoolDef poolDef = _storageResource.getStoragePoolDef(conn, secondaryPool); - tmplVol = _storageResource.getVolume(conn, secondaryPool, poolDef.getTargetPath() + File.separator + tmpltname); /*Copy volume to primary storage*/ - primaryPool = _storageResource.getStoragePool(conn, cmd.getPoolUuid()); - LibvirtStorageVolumeDef vol = new LibvirtStorageVolumeDef(UUID.randomUUID().toString(), tmplVol.getInfo().capacity, volFormat.QCOW2, null, null); - s_logger.debug(vol.toString()); - primaryVol = _storageResource.copyVolume(primaryPool, vol, tmplVol, _cmdsTimeout); + KVMStoragePool primaryPool = _storagePoolMgr.getStoragePool(cmd.getPoolUuid()); - StorageVolInfo priVolInfo = primaryVol.getInfo(); - return new PrimaryStorageDownloadAnswer(primaryVol.getKey(), priVolInfo.allocation); - } catch (LibvirtException e) { - s_logger.debug(e.toString()); + KVMPhysicalDisk primaryVol = _storagePoolMgr.copyPhysicalDisk(tmplVol, UUID.randomUUID().toString(), primaryPool); + + return new PrimaryStorageDownloadAnswer(primaryVol.getName(), primaryVol.getSize()); + } catch (CloudRuntimeException e) { return new PrimaryStorageDownloadAnswer(e.toString()); - } catch (URISyntaxException e) { - return new PrimaryStorageDownloadAnswer(e.toString()); - } finally { - try { - if (primaryVol != null) { - primaryVol.free(); - } - - if (primaryPool != null) { - primaryPool.free(); - } - - if (tmplVol != null) { - tmplVol.free(); - } - - _storageResource.deleteStoragePool(conn, secondaryPool); - - } catch (LibvirtException l) { - - } } - } protected Answer execute(CreateStoragePoolCommand cmd) { @@ -1538,29 +1502,18 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv } protected Answer execute(ModifyStoragePoolCommand cmd) { - try { - Connect conn = LibvirtConnection.getConnection(); - StoragePool storagePool = _storageResource.getStoragePool(conn, cmd.getPool()); - if (storagePool == null) { - return new Answer(cmd, false, " Failed to create storage pool"); - } - - StoragePoolInfo spi = null; - - spi = storagePool.getInfo(); - - Map tInfo = new HashMap(); - ModifyStoragePoolAnswer answer = new ModifyStoragePoolAnswer(cmd, - spi.capacity, - spi.allocation, - tInfo); - - storagePool.free(); - return answer; - } catch (LibvirtException e) { - return new Answer(cmd, false, e.getMessage()); + KVMStoragePool storagepool = _storagePoolMgr.createStoragePool(cmd.getPool().getUuid(), cmd.getPool().getHost(), cmd.getPool().getPath(), cmd.getPool().getType()); + if (storagepool == null) { + return new Answer(cmd, false, " Failed to create storage pool"); } - + + Map tInfo = new HashMap(); + ModifyStoragePoolAnswer answer = new ModifyStoragePoolAnswer(cmd, + storagepool.getCapacity(), + storagepool.getUsed(), + tInfo); + + return answer; } private Answer execute(SecurityIngressRulesCmd cmd) { @@ -2261,8 +2214,13 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv private String getVolumePath(Connect conn, VolumeTO volume) throws LibvirtException, URISyntaxException { if (volume.getType() == Volume.Type.ISO && volume.getPath() != null) { - StorageVol vol = _storageResource.getVolumeFromURI(conn, volume.getPath()); - return vol.getPath(); + String isoPath = volume.getPath(); + int index = isoPath.lastIndexOf("/"); + String path = isoPath.substring(0, index); + String name = isoPath.substring(index + 1); + KVMStoragePool secondaryPool = _storagePoolMgr.getStoragePoolByURI(path); + KVMPhysicalDisk isoVol = secondaryPool.getPhysicalDisk(name); + return isoVol.getPath(); } else { return volume.getPath(); } @@ -2270,7 +2228,21 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv protected void createVbd(Connect conn, VirtualMachineTO vmSpec, String vmName, LibvirtVMDef vm) throws InternalErrorException, LibvirtException, URISyntaxException{ for (VolumeTO volume : vmSpec.getDisks()) { - String volPath = getVolumePath(conn, volume); + KVMPhysicalDisk physicalDisk = null; + KVMStoragePool pool = null; + if (volume.getType() == Volume.Type.ISO && volume.getPath() != null) { + String volPath = volume.getPath(); + int index = volPath.lastIndexOf("/"); + String volDir = volPath.substring(0, index); + String volName = volPath.substring(index + 1); + KVMStoragePool secondaryStorage = _storagePoolMgr.getStoragePoolByURI(volDir); + physicalDisk = secondaryStorage.getPhysicalDisk(volName); + } else { + pool = _storagePoolMgr.getStoragePool(volume.getPoolUuid()); + physicalDisk = pool.getPhysicalDisk(volume.getPath()); + } + + String volPath = physicalDisk.getPath(); DiskDef.diskBus diskBusType = getGuestDiskModel(vmSpec.getOs()); DiskDef disk = new DiskDef(); @@ -2283,8 +2255,11 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv } } else { int devId = (int)volume.getDeviceId(); - - disk.defFileBasedDisk(volume.getPath(), devId, diskBusType, DiskDef.diskFmtType.QCOW2); + if (pool.getType() == StoragePoolType.CLVM) { + disk.defBlockBasedDisk(physicalDisk.getPath(), devId, diskBusType); + } else { + disk.defFileBasedDisk(physicalDisk.getPath(), devId, diskBusType, DiskDef.diskFmtType.QCOW2); + } } //Centos doesn't support scsi hotplug. For other host OSes, we attach the disk after the vm is running, so that we can hotplug it. @@ -2323,20 +2298,30 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv List disks = vm.getDevices().getDisks(); DiskDef rootDisk = disks.get(0); VolumeTO rootVol = getVolume(vmSpec, Volume.Type.ROOT); - StoragePool pool = _storageResource.getStoragePool(conn, rootVol.getPoolUuid()); - StorageVol tmplVol = _storageResource.createTmplDataDisk(conn, pool, 10L * 1024 * 1024); - String datadiskPath = tmplVol.getKey(); + KVMStoragePool pool = _storagePoolMgr.getStoragePool(rootVol.getPoolUuid()); + KVMPhysicalDisk disk = pool.createPhysicalDisk(UUID.randomUUID().toString(), KVMPhysicalDisk.PhysicalDiskFormat.RAW, 10L * 1024 * 1024); + /*Format/create fs on this disk*/ + final Script command = new Script(_createvmPath, _timeout, s_logger); + command.add("-f", disk.getPath()); + String result = command.execute(); + if (result != null) { + s_logger.debug("Failed to create data disk: " + result); + throw new InternalErrorException("Failed to create data disk: " + result); + } + String datadiskPath = disk.getPath(); /*add patch disk*/ DiskDef patchDisk = new DiskDef(); - patchDisk.defFileBasedDisk(rootDisk.getDiskPath(), 1, rootDisk.getBusType(), DiskDef.diskFmtType.RAW); + if (pool.getType() == StoragePoolType.CLVM) { + patchDisk.defBlockBasedDisk(datadiskPath, 1, rootDisk.getBusType()); + } else { + patchDisk.defFileBasedDisk(datadiskPath, 1, rootDisk.getBusType(), DiskDef.diskFmtType.RAW); + } disks.add(patchDisk); - patchDisk.setDiskPath(datadiskPath); String bootArgs = vmSpec.getBootArgs(); patchSystemVm(bootArgs, datadiskPath, vmName); - } private String createVlanBr(String vlanId, String nic) throws InternalErrorException{ @@ -2412,7 +2397,11 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv protected synchronized String attachOrDetachISO(Connect conn, String vmName, String isoPath, boolean isAttach) throws LibvirtException, URISyntaxException, InternalErrorException { String isoXml = null; if (isoPath != null && isAttach) { - StorageVol isoVol = _storageResource.getVolumeFromURI(conn, isoPath); + int index = isoPath.lastIndexOf("/"); + String path = isoPath.substring(0, index); + String name = isoPath.substring(index + 1); + KVMStoragePool secondaryPool = _storagePoolMgr.getStoragePoolByURI(path); + KVMPhysicalDisk isoVol = secondaryPool.getPhysicalDisk(name); isoPath = isoVol.getPath(); DiskDef iso = new DiskDef(); @@ -2548,14 +2537,16 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv StartupStorageCommand sscmd = null; try { - Connect conn = LibvirtConnection.getConnection(); - com.cloud.agent.api.StoragePoolInfo pi = _storageResource.initializeLocalStorage(conn, _localStoragePath, cmd.getPrivateIpAddress(), _localStorageUUID); + + KVMStoragePool localStoragePool = _storagePoolMgr.createStoragePool(_localStorageUUID, "localhost", _localStoragePath, StoragePoolType.Filesystem); + com.cloud.agent.api.StoragePoolInfo pi = new com.cloud.agent.api.StoragePoolInfo(localStoragePool.getUuid(), cmd.getPrivateIpAddress(), _localStoragePath, _localStoragePath, StoragePoolType.Filesystem, localStoragePool.getCapacity(), localStoragePool.getUsed()); + sscmd = new StartupStorageCommand(); sscmd.setPoolInfo(pi); sscmd.setGuid(pi.getUuid()); sscmd.setDataCenter(_dcId); sscmd.setResourceType(Storage.StorageResourceType.STORAGE_POOL); - } catch (LibvirtException e) { + } catch (CloudRuntimeException e) { } diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtConnection.java b/agent/src/com/cloud/agent/resource/computing/LibvirtConnection.java index 92c40aa93f2..1d05e6a1618 100644 --- a/agent/src/com/cloud/agent/resource/computing/LibvirtConnection.java +++ b/agent/src/com/cloud/agent/resource/computing/LibvirtConnection.java @@ -22,6 +22,8 @@ import org.apache.log4j.Logger; import org.libvirt.Connect; import org.libvirt.LibvirtException; +import com.cloud.agent.kvm.KVMConnection; + public class LibvirtConnection { private static final Logger s_logger = Logger.getLogger(LibvirtConnection.class); static private Connect _connection; diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolDef.java b/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolDef.java index 4c93877c25f..c3e38a1e440 100644 --- a/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolDef.java +++ b/agent/src/com/cloud/agent/resource/computing/LibvirtStoragePoolDef.java @@ -22,6 +22,7 @@ public class LibvirtStoragePoolDef { public enum poolType { ISCSI("iscsi"), NETFS("netfs"), + LOGICAL("logical"), DIR("dir"); String _poolType; poolType(String poolType) { diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtStorageResource.java b/agent/src/com/cloud/agent/resource/computing/LibvirtStorageResource.java deleted file mode 100644 index 4143d01548c..00000000000 --- a/agent/src/com/cloud/agent/resource/computing/LibvirtStorageResource.java +++ /dev/null @@ -1,491 +0,0 @@ -/** - * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. - * - * This software is licensed under the GNU General Public License v3 or later. - * - * It is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package com.cloud.agent.resource.computing; - -import java.io.File; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.log4j.Logger; -import org.libvirt.Connect; -import org.libvirt.LibvirtException; -import org.libvirt.StoragePool; -import org.libvirt.StoragePoolInfo; -import org.libvirt.StorageVol; -import org.libvirt.StoragePoolInfo.StoragePoolState; - -import com.cloud.agent.api.StartupStorageCommand; -import com.cloud.agent.api.to.StorageFilerTO; -import com.cloud.agent.api.to.VolumeTO; -import com.cloud.agent.resource.computing.KVMHABase.PoolType; -import com.cloud.agent.resource.computing.LibvirtStoragePoolDef.poolType; -import com.cloud.agent.resource.computing.LibvirtStorageVolumeDef.volFormat; -import com.cloud.exception.InternalErrorException; -import com.cloud.hypervisor.xen.resource.CitrixResourceBase.SRType; -import com.cloud.storage.Storage.StoragePoolType; -import com.cloud.storage.Storage; -import com.cloud.storage.StorageLayer; -import com.cloud.utils.script.Script; - -public class LibvirtStorageResource { - private static final Logger s_logger = Logger.getLogger(LibvirtStorageResource.class); - private LibvirtComputingResource _computingResource; - private final Map _storagePools = new ConcurrentHashMap(); - private StorageLayer _storageLayer; - private String _createvmPath; - private int _timeout; - private String _mountPoint; - private KVMHAMonitor _monitor; - - public LibvirtStorageResource(LibvirtComputingResource resource, StorageLayer storage, String createDiskScript, int timeout, - String mountPoint, KVMHAMonitor monitor) { - _computingResource = resource; - _storageLayer = storage; - _createvmPath = createDiskScript; - _timeout = timeout; - _mountPoint = mountPoint; - _monitor = monitor; - } - public StoragePool getStoragePool(Connect conn, String uuid) throws LibvirtException { - StoragePool storage = null; - try { - storage = conn.storagePoolLookupByUUIDString(uuid); - } catch (LibvirtException e) { - throw e; - } - - if ( storage.getInfo().state != StoragePoolState.VIR_STORAGE_POOL_RUNNING) { - storage.create(0); - } - return storage; - } - - public boolean deleteStoragePool(Connect conn, StorageFilerTO spt) throws LibvirtException { - StoragePool pool = getStoragePool(conn, spt.getUuid()); - LibvirtStoragePoolDef spd = getStoragePoolDef(conn, pool); - - synchronized (getStoragePool(pool.getUUIDString())) { - pool.destroy(); - pool.undefine(); - } - - - - if (spd.getPoolType() == poolType.NETFS) { - KVMHABase.NfsStoragePool sp = new KVMHABase.NfsStoragePool(spt.getUuid(), - spt.getHost(), - spt.getPath(), - spd.getTargetPath(), - PoolType.PrimaryStorage); - _monitor.removeStoragePool(sp); - } - rmStoragePool(spt.getUuid()); - return true; - } - - public boolean deleteStoragePool(Connect conn, StoragePool pool) throws LibvirtException { - if (pool != null) { - String uuid = pool.getUUIDString(); - synchronized (getStoragePool(uuid)) { - pool.destroy(); - pool.undefine(); - pool.free(); - } - rmStoragePool(uuid); - } - return true; - } - - public StorageVol getVolume(Connect conn, StoragePool pool, String volPath) throws LibvirtException { - StorageVol vol = null; - try { - vol = conn.storageVolLookupByKey(volPath); - } catch (LibvirtException e) { - - } - if (vol == null) { - storagePoolRefresh(pool); - vol = conn.storageVolLookupByKey(volPath); - } - return vol; - } - - public StorageVol createVolumeFromTempl(StoragePool destPool, StorageVol tmplVol) throws LibvirtException { - if (_computingResource.isCentosHost()) { - LibvirtStorageVolumeDef volDef = new LibvirtStorageVolumeDef(UUID.randomUUID().toString(), tmplVol.getInfo().capacity, volFormat.QCOW2, null, null); - s_logger.debug(volDef.toString()); - StorageVol vol = destPool.storageVolCreateXML(volDef.toString(), 0); - - /*create qcow2 image based on the name*/ - Script.runSimpleBashScript("qemu-img create -f qcow2 -b " + tmplVol.getPath() + " " + vol.getPath() ); - return vol; - } else { - LibvirtStorageVolumeDef volDef = new LibvirtStorageVolumeDef(UUID.randomUUID().toString(), tmplVol.getInfo().capacity, volFormat.QCOW2, tmplVol.getPath(), volFormat.QCOW2); - s_logger.debug(volDef.toString()); - return destPool.storageVolCreateXML(volDef.toString(), 0); - } - } - - private void addStoragePool(String uuid) { - synchronized (_storagePools) { - if (!_storagePools.containsKey(uuid)) { - _storagePools.put(uuid, new Object()); - } - } - } - - private void rmStoragePool(String uuid) { - synchronized (_storagePools) { - if (_storagePools.containsKey(uuid)) { - _storagePools.remove(uuid); - } - } - } - - private Object getStoragePool(String uuid) { - synchronized (_storagePools) { - if (!_storagePools.containsKey(uuid)) { - addStoragePool(uuid); - } - return _storagePools.get(uuid); - } - } - - - public StorageVol createTmplDataDisk(Connect conn, StoragePool pool, long size) throws LibvirtException, InternalErrorException { - /*create a templ data disk, to contain patches*/ - LibvirtStorageVolumeDef volDef = new LibvirtStorageVolumeDef(UUID.randomUUID().toString(), size, volFormat.RAW, null, null); - StorageVol dataVol = pool.storageVolCreateXML(volDef.toString(), 0); - - /*Format/create fs on this disk*/ - final Script command = new Script(_createvmPath, _timeout, s_logger); - command.add("-f", dataVol.getKey()); - String result = command.execute(); - if (result != null) { - s_logger.debug("Failed to create data disk: " + result); - throw new InternalErrorException("Failed to create data disk: " + result); - } - return dataVol; - } - - public StorageVol createVolume(Connect conn, StoragePool pool, String uuid, long size, volFormat format) throws LibvirtException { - LibvirtStorageVolumeDef volDef = new LibvirtStorageVolumeDef(UUID.randomUUID().toString(), size, format, null, null); - s_logger.debug(volDef.toString()); - return pool.storageVolCreateXML(volDef.toString(), 0); - } - - public StoragePool getStoragePoolbyURI(Connect conn, URI uri) throws LibvirtException { - String sourcePath; - String uuid; - String sourceHost = ""; - String protocal; - if (uri.getScheme().equalsIgnoreCase("local")) { - sourcePath = _mountPoint + File.separator + uri.toString().replace("local:///", ""); - sourcePath = sourcePath.replace("//", "/"); - uuid = UUID.nameUUIDFromBytes(new String(sourcePath).getBytes()).toString(); - protocal = "DIR"; - } else { - sourcePath = uri.getPath(); - sourcePath = sourcePath.replace("//", "/"); - sourceHost = uri.getHost(); - uuid = UUID.nameUUIDFromBytes(new String(sourceHost + sourcePath).getBytes()).toString(); - protocal = "NFS"; - } - - - String targetPath = _mountPoint + File.separator + uuid; - StoragePool sp = null; - try { - sp = conn.storagePoolLookupByUUIDString(uuid); - } catch (LibvirtException e) { - } - - if (sp == null) { - try { - LibvirtStoragePoolDef spd = null; - if (protocal.equalsIgnoreCase("NFS")) { - _storageLayer.mkdir(targetPath); - spd = new LibvirtStoragePoolDef(poolType.NETFS, uuid, uuid, - sourceHost, sourcePath, targetPath); - s_logger.debug(spd.toString()); - addStoragePool(uuid); - - } else if (protocal.equalsIgnoreCase("DIR")) { - _storageLayer.mkdir(targetPath); - spd = new LibvirtStoragePoolDef(poolType.DIR, uuid, uuid, - null, null, sourcePath); - } - - synchronized (getStoragePool(uuid)) { - sp = conn.storagePoolDefineXML(spd.toString(), 0); - - if (sp == null) { - s_logger.debug("Failed to define storage pool"); - return null; - } - sp.create(0); - } - - return sp; - } catch (LibvirtException e) { - try { - if (sp != null) { - sp.undefine(); - sp.free(); - } - } catch (LibvirtException l) { - - } - throw e; - } - } else { - StoragePoolInfo spi = sp.getInfo(); - if (spi.state != StoragePoolState.VIR_STORAGE_POOL_RUNNING) { - sp.create(0); - } - return sp; - } - } - - public void storagePoolRefresh(StoragePool pool) { - try { - synchronized (getStoragePool(pool.getUUIDString())) { - pool.refresh(0); - } - } catch (LibvirtException e) { - - } - } - - private StoragePool createNfsStoragePool(Connect conn, StorageFilerTO pool) { - String targetPath = _mountPoint + File.separator + pool.getUuid(); - LibvirtStoragePoolDef spd = new LibvirtStoragePoolDef(poolType.NETFS, pool.getUuid(), pool.getUuid(), - pool.getHost(), pool.getPath(), targetPath); - _storageLayer.mkdir(targetPath); - StoragePool sp = null; - try { - s_logger.debug(spd.toString()); - addStoragePool(pool.getUuid()); - - synchronized (getStoragePool(pool.getUuid())) { - sp = conn.storagePoolDefineXML(spd.toString(), 0); - sp.create(0); - } - return sp; - } catch (LibvirtException e) { - s_logger.debug(e.toString()); - if (sp != null) { - try { - sp.undefine(); - sp.free(); - } catch (LibvirtException l) { - s_logger.debug("Failed to define nfs storage pool with: " + l.toString()); - } - } - return null; - } - } - - private StoragePool CreateSharedStoragePool(Connect conn, StorageFilerTO pool) { - String mountPoint = pool.getPath(); - if (!_storageLayer.exists(mountPoint)) { - return null; - } - LibvirtStoragePoolDef spd = new LibvirtStoragePoolDef(poolType.DIR, pool.getUuid(), pool.getUuid(), - pool.getHost(), pool.getPath(), pool.getPath()); - StoragePool sp = null; - try { - s_logger.debug(spd.toString()); - addStoragePool(pool.getUuid()); - synchronized (getStoragePool(pool.getUuid())) { - sp = conn.storagePoolDefineXML(spd.toString(), 0); - sp.create(0); - } - return sp; - } catch (LibvirtException e) { - s_logger.debug(e.toString()); - if (sp != null) { - try { - sp.undefine(); - sp.free(); - } catch (LibvirtException l) { - s_logger.debug("Failed to define shared mount point storage pool with: " + l.toString()); - } - } - return null; - } - } - - public StoragePool getStoragePool(Connect conn, StorageFilerTO spt) { - StoragePool sp = null; - try { - sp = conn.storagePoolLookupByUUIDString(spt.getUuid()); - } catch (LibvirtException e) { - - } - - if (sp == null) { - if (spt.getType() == StoragePoolType.NetworkFilesystem) { - sp = createNfsStoragePool(conn, spt); - } else if (spt.getType() == StoragePoolType.SharedMountPoint) { - sp = CreateSharedStoragePool(conn, spt); - } - if (sp == null) { - s_logger.debug("Failed to create storage Pool"); - return null; - } - } - - try { - StoragePoolInfo spi = sp.getInfo(); - if (spi.state != StoragePoolState.VIR_STORAGE_POOL_RUNNING) { - sp.create(0); - } - } catch (LibvirtException e) { - - } - - if (spt.getType() == StoragePoolType.NetworkFilesystem) { - KVMHABase.NfsStoragePool pool = new KVMHABase.NfsStoragePool(spt.getUuid(), - spt.getHost(), - spt.getPath(), - _mountPoint + File.separator + spt.getUuid(), - PoolType.PrimaryStorage); - _monitor.addStoragePool(pool); - } - - addStoragePool(spt.getUuid()); - - return sp; - } - - public StorageVol copyVolume(StoragePool destPool, LibvirtStorageVolumeDef destVol, StorageVol srcVol, int timeout) throws LibvirtException { - StorageVol vol = destPool.storageVolCreateXML(destVol.toString(), 0); - String srcPath = srcVol.getKey(); - String destPath = vol.getKey(); - Script.runSimpleBashScript("cp " + srcPath + " " + destPath, timeout); - return vol; - } - - public boolean copyVolume(String srcPath, String destPath, String volumeName, int timeout) throws InternalErrorException{ - _storageLayer.mkdirs(destPath); - if (!_storageLayer.exists(srcPath)) { - throw new InternalErrorException("volume:" + srcPath + " is not exits"); - } - String result = Script.runSimpleBashScript("cp " + srcPath + " " + destPath + File.separator + volumeName, timeout); - if (result != null) { - return false; - } else { - return true; - } - } - - public LibvirtStoragePoolDef getStoragePoolDef(Connect conn, StoragePool pool) throws LibvirtException { - String poolDefXML = pool.getXMLDesc(0); - LibvirtStoragePoolXMLParser parser = new LibvirtStoragePoolXMLParser(); - return parser.parseStoragePoolXML(poolDefXML); - } - - public StorageVol getVolumeFromURI(Connect conn, String volPath) throws LibvirtException, URISyntaxException { - int index = volPath.lastIndexOf("/"); - URI volDir = null; - StoragePool sp = null; - StorageVol vol = null; - try { - volDir = new URI(volPath.substring(0, index)); - String volName = volPath.substring(index + 1); - sp = getStoragePoolbyURI(conn, volDir); - vol = sp.storageVolLookupByName(volName); - return vol; - } catch (LibvirtException e) { - s_logger.debug("Faild to get vol path: " + e.toString()); - throw e; - } finally { - try { - if (sp != null) { - sp.free(); - } - } catch (LibvirtException e) { - - } - } - } - - public com.cloud.agent.api.StoragePoolInfo initializeLocalStorage(Connect conn, String localStoragePath, String hostIp, String uuid) { - if (!(_storageLayer.exists(localStoragePath) && _storageLayer.isDirectory(localStoragePath))) { - return null; - } - - File path = new File(localStoragePath); - if (!(path.canWrite() && path.canRead() && path.canExecute())) { - return null; - } - StoragePool pool = null; - try { - pool = conn.storagePoolLookupByUUIDString(uuid); - } catch (LibvirtException e) { - - } - - if (pool == null) { - LibvirtStoragePoolDef spd = new LibvirtStoragePoolDef(poolType.DIR, uuid, uuid, - null, null, localStoragePath); - try { - pool = conn.storagePoolDefineXML(spd.toString(), 0); - pool.create(0); - } catch (LibvirtException e) { - if (pool != null) { - try { - pool.destroy(); - pool.undefine(); - } catch (LibvirtException e1) { - } - pool = null; - } - } - } - - if (pool == null) { - return null; - } - - try { - StoragePoolInfo spi = pool.getInfo(); - if (spi.state != StoragePoolState.VIR_STORAGE_POOL_RUNNING) { - pool.create(0); - } - - spi = pool.getInfo(); - if (spi.state != StoragePoolState.VIR_STORAGE_POOL_RUNNING) { - return null; - } - com.cloud.agent.api.StoragePoolInfo pInfo = new com.cloud.agent.api.StoragePoolInfo(uuid, hostIp, localStoragePath, localStoragePath, StoragePoolType.Filesystem, spi.capacity, spi.available); - - return pInfo; - } catch (LibvirtException e) { - - } - - return null; - } - -} diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtStorageVolumeDef.java b/agent/src/com/cloud/agent/resource/computing/LibvirtStorageVolumeDef.java index caa71614b9a..1769a26ac4e 100644 --- a/agent/src/com/cloud/agent/resource/computing/LibvirtStorageVolumeDef.java +++ b/agent/src/com/cloud/agent/resource/computing/LibvirtStorageVolumeDef.java @@ -46,6 +46,9 @@ public class LibvirtStorageVolumeDef { _backingFormat = tmplFormat; } + public volFormat getFormat() { + return this._volFormat; + } @Override public String toString() { StringBuilder storageVolBuilder = new StringBuilder(); diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtStorageVolumeXMLParser.java b/agent/src/com/cloud/agent/resource/computing/LibvirtStorageVolumeXMLParser.java new file mode 100644 index 00000000000..42dbd890549 --- /dev/null +++ b/agent/src/com/cloud/agent/resource/computing/LibvirtStorageVolumeXMLParser.java @@ -0,0 +1,90 @@ +package com.cloud.agent.resource.computing; + +import java.io.IOException; +import java.io.StringReader; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +public class LibvirtStorageVolumeXMLParser{ + private static final Logger s_logger = Logger.getLogger(LibvirtStorageVolumeXMLParser.class); + public LibvirtStorageVolumeDef parseStorageVolumeXML(String volXML) { + DocumentBuilder builder; + try { + builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + + InputSource is = new InputSource(); + is.setCharacterStream(new StringReader(volXML)); + Document doc = builder.parse(is); + + Element rootElement = doc.getDocumentElement(); + + String VolName = getTagValue("name", rootElement); + Element target = (Element)rootElement.getElementsByTagName("target").item(0); + String format = getAttrValue("type", "format", target); + Long capacity = Long.parseLong(getTagValue("capacity", rootElement)); + return new LibvirtStorageVolumeDef(VolName, capacity, LibvirtStorageVolumeDef.volFormat.QCOW2, null, null); + } catch (ParserConfigurationException e) { + s_logger.debug(e.toString()); + } catch (SAXException e) { + s_logger.debug(e.toString()); + } catch (IOException e) { + s_logger.debug(e.toString()); + } + return null; + } + + private static String getTagValue(String tag, Element eElement){ + NodeList nlList= eElement.getElementsByTagName(tag).item(0).getChildNodes(); + Node nValue = (Node) nlList.item(0); + + return nValue.getNodeValue(); + } + + private static String getAttrValue(String tag, String attr, Element eElement){ + NodeList tagNode = eElement.getElementsByTagName(tag); + if (tagNode.getLength() == 0) { + return null; + } + Element node = (Element)tagNode.item(0); + return node.getAttribute(attr); + } + + + public static void main(String[] args) { + s_logger.addAppender(new org.apache.log4j.ConsoleAppender(new org.apache.log4j.PatternLayout(), "System.out")); + String storagePool = "" + + "test" + + "bf723c83-4b95-259c-7089-60776e61a11f" + + "20314165248" + + "1955450880" + + "18358714368" + + "" + + "" + + "" + + "" + + "" + + "" + + "/media" + + "" + + "0700" + + "0" + + "0" + + "" + + "" + + ""; + + LibvirtStoragePoolXMLParser parser = new LibvirtStoragePoolXMLParser(); + LibvirtStoragePoolDef pool = parser.parseStoragePoolXML(storagePool); + s_logger.debug(pool.toString()); + } +} diff --git a/agent/src/com/cloud/agent/resource/computing/LibvirtVMDef.java b/agent/src/com/cloud/agent/resource/computing/LibvirtVMDef.java index 607385948cb..9fc99428dc4 100644 --- a/agent/src/com/cloud/agent/resource/computing/LibvirtVMDef.java +++ b/agent/src/com/cloud/agent/resource/computing/LibvirtVMDef.java @@ -337,11 +337,12 @@ public class LibvirtVMDef { _diskFmtType = diskFmtType.RAW; _bus = diskBus.IDE; } - public void defBlockBasedDisk(String diskName, String diskLabel, diskBus bus) { + public void defBlockBasedDisk(String diskName, int devId, diskBus bus) { _diskType = diskType.BLOCK; _deviceType = deviceType.DISK; + _diskFmtType = diskFmtType.RAW; _sourcePath = diskName; - _diskLabel = diskLabel; + _diskLabel = getDevLabel(devId, bus); _bus = bus; } public void setReadonly() { diff --git a/agent/src/com/cloud/agent/storage/KVMPhysicalDisk.java b/agent/src/com/cloud/agent/storage/KVMPhysicalDisk.java new file mode 100644 index 00000000000..282a14feb21 --- /dev/null +++ b/agent/src/com/cloud/agent/storage/KVMPhysicalDisk.java @@ -0,0 +1,56 @@ +package com.cloud.agent.storage; + +public class KVMPhysicalDisk { + private String path; + private String name; + private KVMStoragePool pool; + public static enum PhysicalDiskFormat { + RAW, + QCOW2 + } + private PhysicalDiskFormat format; + private long size; + private long virtualSize; + + public KVMPhysicalDisk(String path, String name, KVMStoragePool pool) { + this.path = path; + this.name = name; + this.pool = pool; + } + + public void setFormat(PhysicalDiskFormat format) { + this.format = format; + } + + public PhysicalDiskFormat getFormat() { + return this.format; + } + + public void setSize(long size) { + this.size = size; + } + + public long getSize() { + return this.size; + } + + public void setVirtualSize(long size) { + this.virtualSize = size; + } + + public long getVirtualSize() { + return this.virtualSize; + } + + public String getName() { + return this.name; + } + + public String getPath() { + return this.path; + } + + public KVMStoragePool getPool() { + return this.pool; + } +} diff --git a/agent/src/com/cloud/agent/storage/KVMStoragePool.java b/agent/src/com/cloud/agent/storage/KVMStoragePool.java new file mode 100644 index 00000000000..19d5486c8ac --- /dev/null +++ b/agent/src/com/cloud/agent/storage/KVMStoragePool.java @@ -0,0 +1,21 @@ +package com.cloud.agent.storage; + +import java.util.List; + +import com.cloud.agent.storage.KVMPhysicalDisk.PhysicalDiskFormat; +import com.cloud.storage.Storage.StoragePoolType; + +public interface KVMStoragePool { + public KVMPhysicalDisk createPhysicalDisk(String name, PhysicalDiskFormat format, long size); + public KVMPhysicalDisk createPhysicalDisk(String name, long size); + public KVMPhysicalDisk getPhysicalDisk(String volumeUuid); + public boolean deletePhysicalDisk(String uuid); + public List listPhysicalDisks(); + public String getUuid(); + public long getCapacity(); + public long getUsed(); + public boolean refresh(); + public boolean isExternalSnapshot(); + public String getLocalPath(); + public StoragePoolType getType(); +} diff --git a/agent/src/com/cloud/agent/storage/KVMStoragePoolManager.java b/agent/src/com/cloud/agent/storage/KVMStoragePoolManager.java new file mode 100644 index 00000000000..99e62d9aaf2 --- /dev/null +++ b/agent/src/com/cloud/agent/storage/KVMStoragePoolManager.java @@ -0,0 +1,77 @@ +package com.cloud.agent.storage; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import com.cloud.agent.storage.KVMPhysicalDisk.PhysicalDiskFormat; +import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.StorageLayer; + +public class KVMStoragePoolManager { + private StorageAdaptor _storageAdaptor; + private final Map _storagePools = new ConcurrentHashMap(); + + private void addStoragePool(String uuid) { + synchronized (_storagePools) { + if (!_storagePools.containsKey(uuid)) { + _storagePools.put(uuid, new Object()); + } + } + } + public KVMStoragePoolManager(StorageLayer storagelayer) { + this._storageAdaptor = new LibvirtStorageAdaptor(storagelayer); + } + + public KVMStoragePool getStoragePool(String uuid) { + return this._storageAdaptor.getStoragePool(uuid); + } + + public KVMStoragePool getStoragePoolByURI(String uri) { + return this._storageAdaptor.getStoragePoolByUri(uri); + } + + public KVMStoragePool createStoragePool(String name, String host, String path, StoragePoolType type) { + KVMStoragePool pool = this._storageAdaptor.createStoragePool(name, host, path, type); + if (type == StoragePoolType.NetworkFilesystem || type == StoragePoolType.SharedMountPoint) { + /* + KVMHABase.NfsStoragePool pool = new KVMHABase.NfsStoragePool(spt.getUuid(), + spt.getHost(), + spt.getPath(), + _mountPoint + File.separator + spt.getUuid(), + PoolType.PrimaryStorage); + _monitor.addStoragePool(pool); + */ + } + addStoragePool(pool.getUuid()); + return pool; + } + + public boolean deleteStoragePool(String uuid) { + this._storageAdaptor.deleteStoragePool(uuid); + _storagePools.remove(uuid); + return true; + } + + public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template, String name, KVMStoragePool destPool) { + if (destPool.getType() == StoragePoolType.CLVM) { + return this._storageAdaptor.createDiskFromTemplate(template, name, KVMPhysicalDisk.PhysicalDiskFormat.RAW, template.getSize(), destPool); + } else { + return this._storageAdaptor.createDiskFromTemplate(template, name, KVMPhysicalDisk.PhysicalDiskFormat.QCOW2, template.getSize(), destPool); + } + } + + public KVMPhysicalDisk createTemplateFromDisk(KVMPhysicalDisk disk, String name, PhysicalDiskFormat format, long size, KVMStoragePool destPool) { + return this._storageAdaptor.createTemplateFromDisk(disk, name, format, size, destPool); + } + + public KVMPhysicalDisk copyPhysicalDisk(KVMPhysicalDisk disk, String name, KVMStoragePool destPool) { + return this._storageAdaptor.copyPhysicalDisk(disk, name, destPool); + } + + public KVMPhysicalDisk createDiskFromSnapshot(KVMPhysicalDisk snapshot, String snapshotName, String name, KVMStoragePool destPool) { + return this._storageAdaptor.createDiskFromSnapshot(snapshot, snapshotName, name, destPool); + } + + public KVMPhysicalDisk getPhysicalDiskFromUrl(String url) { + return this._storageAdaptor.getPhysicalDiskFromURI(url); + } +} diff --git a/agent/src/com/cloud/agent/storage/KVMVirtualDisk.java b/agent/src/com/cloud/agent/storage/KVMVirtualDisk.java new file mode 100644 index 00000000000..af79544fc0f --- /dev/null +++ b/agent/src/com/cloud/agent/storage/KVMVirtualDisk.java @@ -0,0 +1,6 @@ +package com.cloud.agent.storage; + +public class KVMVirtualDisk { + + +} diff --git a/agent/src/com/cloud/agent/storage/LibvirtStorageAdaptor.java b/agent/src/com/cloud/agent/storage/LibvirtStorageAdaptor.java new file mode 100644 index 00000000000..247d289c450 --- /dev/null +++ b/agent/src/com/cloud/agent/storage/LibvirtStorageAdaptor.java @@ -0,0 +1,630 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.cloud.agent.storage; + +import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.log4j.Logger; +import org.libvirt.Connect; +import org.libvirt.LibvirtException; +import org.libvirt.StoragePool; +import org.libvirt.StoragePoolInfo; +import org.libvirt.StorageVol; +import org.libvirt.StoragePoolInfo.StoragePoolState; + +import com.cloud.agent.api.GetStorageStatsAnswer; +import com.cloud.agent.api.StartupStorageCommand; +import com.cloud.agent.api.to.StorageFilerTO; +import com.cloud.agent.api.to.VolumeTO; +import com.cloud.agent.resource.computing.KVMHABase; +import com.cloud.agent.resource.computing.KVMHAMonitor; +import com.cloud.agent.resource.computing.LibvirtComputingResource; +import com.cloud.agent.resource.computing.LibvirtConnection; +import com.cloud.agent.resource.computing.LibvirtStoragePoolDef; +import com.cloud.agent.resource.computing.LibvirtStoragePoolXMLParser; +import com.cloud.agent.resource.computing.LibvirtStorageVolumeDef; +import com.cloud.agent.resource.computing.KVMHABase.NfsStoragePool; +import com.cloud.agent.resource.computing.KVMHABase.PoolType; +import com.cloud.agent.resource.computing.LibvirtStoragePoolDef.poolType; +import com.cloud.agent.resource.computing.LibvirtStorageVolumeDef.volFormat; +import com.cloud.agent.resource.computing.LibvirtStorageVolumeXMLParser; +import com.cloud.agent.storage.KVMPhysicalDisk.PhysicalDiskFormat; +import com.cloud.exception.InternalErrorException; +import com.cloud.hypervisor.xen.resource.CitrixResourceBase.SRType; +import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.Storage; +import com.cloud.storage.StorageLayer; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.script.OutputInterpreter; +import com.cloud.utils.script.Script; + +public class LibvirtStorageAdaptor implements StorageAdaptor { + private static final Logger s_logger = Logger.getLogger(LibvirtStorageAdaptor.class); + private StorageLayer _storageLayer; + private String _mountPoint = "/mnt"; + + + public LibvirtStorageAdaptor(StorageLayer storage + ) { + _storageLayer = storage; + + } + + + public StorageVol getVolume(StoragePool pool, String volName) { + StorageVol vol = null; + + try { + vol = pool.storageVolLookupByName(volName); + } catch (LibvirtException e) { + + } + if (vol == null) { + storagePoolRefresh(pool); + try { + vol = pool.storageVolLookupByName(volName); + } catch (LibvirtException e) { + throw new CloudRuntimeException(e.toString()); + } + } + return vol; + } + + public StorageVol createVolume(Connect conn, StoragePool pool, String uuid, long size, volFormat format) throws LibvirtException { + LibvirtStorageVolumeDef volDef = new LibvirtStorageVolumeDef(UUID.randomUUID().toString(), size, format, null, null); + s_logger.debug(volDef.toString()); + return pool.storageVolCreateXML(volDef.toString(), 0); + } + + public StoragePool getStoragePoolbyURI(Connect conn, URI uri) throws LibvirtException { + String sourcePath; + String uuid; + String sourceHost = ""; + String protocal; + if (uri.getScheme().equalsIgnoreCase("local")) { + sourcePath = _mountPoint + File.separator + uri.toString().replace("local:///", ""); + sourcePath = sourcePath.replace("//", "/"); + uuid = UUID.nameUUIDFromBytes(new String(sourcePath).getBytes()).toString(); + protocal = "DIR"; + } else { + sourcePath = uri.getPath(); + sourcePath = sourcePath.replace("//", "/"); + sourceHost = uri.getHost(); + uuid = UUID.nameUUIDFromBytes(new String(sourceHost + sourcePath).getBytes()).toString(); + protocal = "NFS"; + } + + + String targetPath = _mountPoint + File.separator + uuid; + StoragePool sp = null; + try { + sp = conn.storagePoolLookupByUUIDString(uuid); + } catch (LibvirtException e) { + } + + if (sp == null) { + try { + LibvirtStoragePoolDef spd = null; + if (protocal.equalsIgnoreCase("NFS")) { + _storageLayer.mkdir(targetPath); + spd = new LibvirtStoragePoolDef(poolType.NETFS, uuid, uuid, + sourceHost, sourcePath, targetPath); + s_logger.debug(spd.toString()); + //addStoragePool(uuid); + + } else if (protocal.equalsIgnoreCase("DIR")) { + _storageLayer.mkdir(targetPath); + spd = new LibvirtStoragePoolDef(poolType.DIR, uuid, uuid, + null, null, sourcePath); + } + + synchronized (getStoragePool(uuid)) { + sp = conn.storagePoolDefineXML(spd.toString(), 0); + + if (sp == null) { + s_logger.debug("Failed to define storage pool"); + return null; + } + sp.create(0); + } + + return sp; + } catch (LibvirtException e) { + try { + if (sp != null) { + sp.undefine(); + sp.free(); + } + } catch (LibvirtException l) { + + } + throw e; + } + } else { + StoragePoolInfo spi = sp.getInfo(); + if (spi.state != StoragePoolState.VIR_STORAGE_POOL_RUNNING) { + sp.create(0); + } + return sp; + } + } + + public void storagePoolRefresh(StoragePool pool) { + try { + synchronized (getStoragePool(pool.getUUIDString())) { + pool.refresh(0); + } + } catch (LibvirtException e) { + + } + } + + private StoragePool createNfsStoragePool(Connect conn, String uuid, String host, String path) { + String targetPath = _mountPoint + File.separator + uuid; + LibvirtStoragePoolDef spd = new LibvirtStoragePoolDef(poolType.NETFS, uuid, uuid, + host, path, targetPath); + _storageLayer.mkdir(targetPath); + StoragePool sp = null; + try { + s_logger.debug(spd.toString()); + sp = conn.storagePoolDefineXML(spd.toString(), 0); + sp.create(0); + return sp; + } catch (LibvirtException e) { + s_logger.debug(e.toString()); + if (sp != null) { + try { + sp.undefine(); + sp.free(); + } catch (LibvirtException l) { + s_logger.debug("Failed to define nfs storage pool with: " + l.toString()); + } + } + return null; + } + } + + private StoragePool CreateSharedStoragePool(Connect conn, String uuid, String host, String path) { + String mountPoint = path; + if (!_storageLayer.exists(mountPoint)) { + return null; + } + LibvirtStoragePoolDef spd = new LibvirtStoragePoolDef(poolType.DIR, uuid, uuid, + host, path, path); + StoragePool sp = null; + try { + s_logger.debug(spd.toString()); + sp = conn.storagePoolDefineXML(spd.toString(), 0); + sp.create(0); + + return sp; + } catch (LibvirtException e) { + s_logger.debug(e.toString()); + if (sp != null) { + try { + sp.undefine(); + sp.free(); + } catch (LibvirtException l) { + s_logger.debug("Failed to define shared mount point storage pool with: " + l.toString()); + } + } + return null; + } + } + + public StorageVol copyVolume(StoragePool destPool, LibvirtStorageVolumeDef destVol, StorageVol srcVol, int timeout) throws LibvirtException { + StorageVol vol = destPool.storageVolCreateXML(destVol.toString(), 0); + String srcPath = srcVol.getKey(); + String destPath = vol.getKey(); + Script.runSimpleBashScript("cp " + srcPath + " " + destPath, timeout); + return vol; + } + + public boolean copyVolume(String srcPath, String destPath, String volumeName, int timeout) throws InternalErrorException{ + _storageLayer.mkdirs(destPath); + if (!_storageLayer.exists(srcPath)) { + throw new InternalErrorException("volume:" + srcPath + " is not exits"); + } + String result = Script.runSimpleBashScript("cp " + srcPath + " " + destPath + File.separator + volumeName, timeout); + if (result != null) { + return false; + } else { + return true; + } + } + + public LibvirtStoragePoolDef getStoragePoolDef(Connect conn, StoragePool pool) throws LibvirtException { + String poolDefXML = pool.getXMLDesc(0); + LibvirtStoragePoolXMLParser parser = new LibvirtStoragePoolXMLParser(); + return parser.parseStoragePoolXML(poolDefXML); + } + + public LibvirtStorageVolumeDef getStorageVolumeDef(Connect conn, StorageVol vol) throws LibvirtException { + String volDefXML = vol.getXMLDesc(0); + LibvirtStorageVolumeXMLParser parser = new LibvirtStorageVolumeXMLParser(); + return parser.parseStorageVolumeXML(volDefXML); + } + + public StorageVol getVolumeFromURI(Connect conn, String volPath) throws LibvirtException, URISyntaxException { + int index = volPath.lastIndexOf("/"); + URI volDir = null; + StoragePool sp = null; + StorageVol vol = null; + try { + volDir = new URI(volPath.substring(0, index)); + String volName = volPath.substring(index + 1); + sp = getStoragePoolbyURI(conn, volDir); + vol = sp.storageVolLookupByName(volName); + return vol; + } catch (LibvirtException e) { + s_logger.debug("Faild to get vol path: " + e.toString()); + throw e; + } finally { + try { + if (sp != null) { + sp.free(); + } + } catch (LibvirtException e) { + + } + } + } + + public StoragePool createFileBasedStoragePool(Connect conn, String localStoragePath, String uuid) { + if (!(_storageLayer.exists(localStoragePath) && _storageLayer.isDirectory(localStoragePath))) { + return null; + } + + File path = new File(localStoragePath); + if (!(path.canWrite() && path.canRead() && path.canExecute())) { + return null; + } + + StoragePool pool = null; + + try { + pool = conn.storagePoolLookupByUUIDString(uuid); + } catch (LibvirtException e) { + + } + + if (pool == null) { + LibvirtStoragePoolDef spd = new LibvirtStoragePoolDef(poolType.DIR, uuid, uuid, + null, null, localStoragePath); + try { + pool = conn.storagePoolDefineXML(spd.toString(), 0); + pool.create(0); + } catch (LibvirtException e) { + if (pool != null) { + try { + pool.destroy(); + pool.undefine(); + } catch (LibvirtException e1) { + } + pool = null; + } + throw new CloudRuntimeException(e.toString()); + } + } + + try { + StoragePoolInfo spi = pool.getInfo(); + if (spi.state != StoragePoolState.VIR_STORAGE_POOL_RUNNING) { + pool.create(0); + } + + } catch (LibvirtException e) { + throw new CloudRuntimeException(e.toString()); + } + + return pool; + } + + private void getStats(LibvirtStoragePool pool) { + Script statsScript = new Script("/bin/bash", s_logger); + statsScript.add("-c"); + statsScript.add("stats=$(df --total " + pool.getLocalPath() + " |grep total|awk '{print $2,$3}');echo $stats"); + final OutputInterpreter.OneLineParser statsParser = new OutputInterpreter.OneLineParser(); + String result = statsScript.execute(statsParser); + if (result == null) { + String stats = statsParser.getLine(); + if (stats != null && !stats.isEmpty()) { + String sizes[] = stats.trim().split(" "); + if (sizes.length == 2) { + pool.setCapacity(Long.parseLong(sizes[0]) * 1024); + pool.setUsed(Long.parseLong(sizes[1]) * 1024); + } + } + } + } + + @Override + public KVMStoragePool getStoragePool(String uuid) { + StoragePool storage = null; + try { + Connect conn = LibvirtConnection.getConnection(); + storage = conn.storagePoolLookupByUUIDString(uuid); + + if (storage.getInfo().state != StoragePoolState.VIR_STORAGE_POOL_RUNNING) { + storage.create(0); + } + LibvirtStoragePoolDef spd = getStoragePoolDef(conn, storage); + StoragePoolType type = null; + if (spd.getPoolType() == LibvirtStoragePoolDef.poolType.NETFS || spd.getPoolType() == LibvirtStoragePoolDef.poolType.DIR) { + type = StoragePoolType.Filesystem; + } else if (spd.getPoolType() == LibvirtStoragePoolDef.poolType.LOGICAL) { + type = StoragePoolType.CLVM; + } + LibvirtStoragePool pool = new LibvirtStoragePool(uuid, storage.getName(), type, this, storage); + pool.setLocalPath(spd.getTargetPath()); + + if (pool.getType() == StoragePoolType.CLVM) { + pool.setCapacity(storage.getInfo().capacity); + pool.setUsed(storage.getInfo().allocation); + } else { + getStats(pool); + } + return pool; + } catch (LibvirtException e) { + throw new CloudRuntimeException(e.toString()); + } + } + + @Override + public KVMPhysicalDisk getPhysicalDisk( + String volumeUuid, KVMStoragePool pool) { + LibvirtStoragePool libvirtPool = (LibvirtStoragePool)pool; + + try { + StorageVol vol = this.getVolume(libvirtPool.getPool(), volumeUuid); + KVMPhysicalDisk disk; + LibvirtStorageVolumeDef voldef = getStorageVolumeDef(libvirtPool.getPool().getConnect(), vol); + disk = new KVMPhysicalDisk(vol.getPath(), vol.getName(), pool); + disk.setSize(vol.getInfo().allocation); + disk.setVirtualSize(vol.getInfo().capacity); + if (voldef.getFormat() == LibvirtStorageVolumeDef.volFormat.QCOW2) { + disk.setFormat(KVMPhysicalDisk.PhysicalDiskFormat.QCOW2); + } else if (voldef.getFormat() == LibvirtStorageVolumeDef.volFormat.RAW) { + disk.setFormat(KVMPhysicalDisk.PhysicalDiskFormat.RAW); + } + return disk; + } catch (LibvirtException e) { + throw new CloudRuntimeException(e.toString()); + } + + } + @Override + public KVMStoragePool createStoragePool(String name, String host, String path, StoragePoolType type) { + StoragePool sp = null; + Connect conn = null; + try { + conn = LibvirtConnection.getConnection(); + } catch (LibvirtException e) { + throw new CloudRuntimeException(e.toString()); + } + + try { + sp = conn.storagePoolLookupByUUIDString(name); + } catch (LibvirtException e) { + + } + + if (sp == null) { + if (type == StoragePoolType.NetworkFilesystem) { + sp = createNfsStoragePool(conn, name, host, path); + } else if (type == StoragePoolType.SharedMountPoint || type == StoragePoolType.Filesystem) { + sp = CreateSharedStoragePool(conn, name, host, path); + } + } + + try { + StoragePoolInfo spi = sp.getInfo(); + if (spi.state != StoragePoolState.VIR_STORAGE_POOL_RUNNING) { + sp.create(0); + } + + LibvirtStoragePoolDef spd = getStoragePoolDef(conn, sp); + LibvirtStoragePool pool = new LibvirtStoragePool(name, sp.getName(), type, this, sp); + pool.setLocalPath(spd.getTargetPath()); + + if (pool.getType() == StoragePoolType.CLVM) { + pool.setCapacity(sp.getInfo().capacity); + pool.setUsed(sp.getInfo().allocation); + } else { + getStats(pool); + } + return pool; + } catch (LibvirtException e) { + throw new CloudRuntimeException(e.toString()); + } + + } + @Override + public boolean deleteStoragePool(String uuid) { + Connect conn = null; + try { + conn = LibvirtConnection.getConnection(); + } catch (LibvirtException e) { + throw new CloudRuntimeException(e.toString()); + } + + StoragePool sp = null; + + try { + sp = conn.storagePoolLookupByUUIDString(uuid); + } catch (LibvirtException e) { + return true; + } + + try { + sp.destroy(); + sp.undefine(); + sp.free(); + return true; + } catch (LibvirtException e) { + throw new CloudRuntimeException(e.toString()); + } + } + + @Override + public KVMPhysicalDisk createPhysicalDisk(String name, + KVMStoragePool pool, PhysicalDiskFormat format, long size) { + LibvirtStoragePool libvirtPool = (LibvirtStoragePool)pool; + StoragePool virtPool = libvirtPool.getPool(); + LibvirtStorageVolumeDef.volFormat libvirtformat = null; + if (format == PhysicalDiskFormat.QCOW2) { + libvirtformat = LibvirtStorageVolumeDef.volFormat.QCOW2; + } else if (format == PhysicalDiskFormat.RAW) { + libvirtformat = LibvirtStorageVolumeDef.volFormat.RAW; + } + + LibvirtStorageVolumeDef volDef = new LibvirtStorageVolumeDef(name, size, libvirtformat, null, null); + s_logger.debug(volDef.toString()); + try { + StorageVol vol = virtPool.storageVolCreateXML(volDef.toString(), 0); + KVMPhysicalDisk disk = new KVMPhysicalDisk(vol.getPath(), vol.getName(), pool); + disk.setFormat(format); + disk.setSize(vol.getInfo().allocation); + disk.setVirtualSize(vol.getInfo().capacity); + return disk; + } catch (LibvirtException e) { + throw new CloudRuntimeException(e.toString()); + } + } + @Override + public boolean deletePhysicalDisk(String uuid, KVMStoragePool pool) { + LibvirtStoragePool libvirtPool = (LibvirtStoragePool)pool; + try { + StorageVol vol = this.getVolume(libvirtPool.getPool(), uuid); + vol.delete(0); + vol.free(); + return true; + } catch (LibvirtException e) { + throw new CloudRuntimeException(e.toString()); + } + } + + @Override + public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template, + String name, PhysicalDiskFormat format, long size, + KVMStoragePool destPool) { + KVMPhysicalDisk disk = destPool.createPhysicalDisk(UUID.randomUUID().toString(), format, template.getVirtualSize()); + + if (format == PhysicalDiskFormat.QCOW2) { + Script.runSimpleBashScript("qemu-img create -f qcow2 -b " + template.getPath() + " " + disk.getPath()); + } else { + Script.runSimpleBashScript("cp " + template.getPath() + " " + disk.getPath()); + } + return disk; + } + + @Override + public KVMPhysicalDisk createTemplateFromDisk(KVMPhysicalDisk disk, + String name, PhysicalDiskFormat format, long size, + KVMStoragePool destPool) { + // TODO Auto-generated method stub + return null; + } + + @Override + public List listPhysicalDisks(String storagePoolUuid, KVMStoragePool pool) { + LibvirtStoragePool libvirtPool = (LibvirtStoragePool)pool; + StoragePool virtPool = libvirtPool.getPool(); + List disks = new ArrayList(); + try { + String[] vols = virtPool.listVolumes(); + for (String volName : vols) { + KVMPhysicalDisk disk = this.getPhysicalDisk(volName, pool); + disks.add(disk); + } + return disks; + } catch (LibvirtException e) { + throw new CloudRuntimeException(e.toString()); + } + } + + @Override + public KVMPhysicalDisk copyPhysicalDisk(KVMPhysicalDisk disk, + String name, KVMStoragePool destPool) { + KVMPhysicalDisk newDisk = destPool.createPhysicalDisk(name, disk.getVirtualSize()); + String sourcePath = disk.getPath(); + String destPath = newDisk.getPath(); + Script.runSimpleBashScript("qemu-img convert -f qcow2 -O qcow2 " + sourcePath + " " + destPath); + return newDisk; + } + + @Override + public KVMStoragePool getStoragePoolByUri(String uri) { + URI storageUri = null; + + try { + storageUri = new URI(uri); + } catch (URISyntaxException e) { + throw new CloudRuntimeException(e.toString()); + } + + String sourcePath = null; + String uuid = null; + String sourceHost = ""; + StoragePoolType protocal = null; + if (storageUri.getScheme().equalsIgnoreCase("nfs")) { + sourcePath = storageUri.getPath(); + sourcePath = sourcePath.replace("//", "/"); + sourceHost = storageUri.getHost(); + uuid = UUID.nameUUIDFromBytes(new String(sourceHost + sourcePath).getBytes()).toString(); + protocal = StoragePoolType.NetworkFilesystem; + } + + return createStoragePool(uuid, sourceHost, sourcePath, protocal); + } + + @Override + public KVMPhysicalDisk getPhysicalDiskFromURI(String uri) { + // TODO Auto-generated method stub + return null; + } + + @Override + public KVMPhysicalDisk createDiskFromSnapshot(KVMPhysicalDisk snapshot, + String snapshotName, String name, KVMStoragePool destPool) { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean refresh(KVMStoragePool pool) { + LibvirtStoragePool libvirtPool = (LibvirtStoragePool)pool; + StoragePool virtPool = libvirtPool.getPool(); + try { + virtPool.refresh(0); + } catch (LibvirtException e) { + return false; + } + return true; + } + + +} diff --git a/agent/src/com/cloud/agent/storage/LibvirtStoragePool.java b/agent/src/com/cloud/agent/storage/LibvirtStoragePool.java new file mode 100644 index 00000000000..e94a1d0b828 --- /dev/null +++ b/agent/src/com/cloud/agent/storage/LibvirtStoragePool.java @@ -0,0 +1,131 @@ +package com.cloud.agent.storage; + +import java.util.List; + +import org.libvirt.StoragePool; + +import com.cloud.agent.storage.KVMPhysicalDisk.PhysicalDiskFormat; +import com.cloud.storage.Storage.StoragePoolType; + +public class LibvirtStoragePool implements KVMStoragePool { + protected String uuid; + protected String uri; + protected long capacity; + protected long used; + protected String name; + protected String localPath; + protected PhysicalDiskFormat defaultFormat; + protected StoragePoolType type; + protected StorageAdaptor _storageAdaptor; + protected StoragePool _pool; + + public LibvirtStoragePool(String uuid, String name, StoragePoolType type, StorageAdaptor adaptor, StoragePool pool) { + this.uuid = uuid; + this.name = name; + this.type = type; + this._storageAdaptor = adaptor; + this.capacity = 0; + this.used = 0; + this._pool = pool; + + } + + public void setCapacity(long capacity) { + this.capacity = capacity; + } + + @Override + public long getCapacity() { + return this.capacity; + } + + public void setUsed(long used) { + this.used = used; + } + + @Override + public long getUsed() { + return this.used; + } + + public StoragePoolType getStoragePoolType() { + return this.type; + } + + public String getName() { + return this.name; + } + + public String getUuid() { + return this.uuid; + } + + public String uri() { + return this.uri; + } + + public PhysicalDiskFormat getDefaultFormat() { + if (getStoragePoolType() == StoragePoolType.CLVM) { + return PhysicalDiskFormat.RAW; + } else { + return PhysicalDiskFormat.QCOW2; + } + } + + @Override + public KVMPhysicalDisk createPhysicalDisk(String name, PhysicalDiskFormat format, long size) { + return this._storageAdaptor.createPhysicalDisk(name, this, format, size); + } + + @Override + public KVMPhysicalDisk createPhysicalDisk(String name, long size) { + return this._storageAdaptor.createPhysicalDisk(name, this, this.getDefaultFormat(), size); + } + + @Override + public KVMPhysicalDisk getPhysicalDisk(String volumeUuid) { + return this._storageAdaptor.getPhysicalDisk(volumeUuid, this); + } + + @Override + public boolean deletePhysicalDisk(String uuid) { + return this._storageAdaptor.deletePhysicalDisk(uuid, this); + } + + @Override + public List listPhysicalDisks() { + return this._storageAdaptor.listPhysicalDisks(this.uuid, this); + } + + @Override + public boolean refresh() { + return this._storageAdaptor.refresh(this); + } + + @Override + public boolean isExternalSnapshot() { + if (this.type == StoragePoolType.Filesystem) { + return false; + } + + return true; + } + + @Override + public String getLocalPath() { + return this.localPath; + } + + public void setLocalPath(String localPath) { + this.localPath = localPath; + } + + @Override + public StoragePoolType getType() { + return this.type; + } + + public StoragePool getPool() { + return this._pool; + } +} diff --git a/agent/src/com/cloud/agent/storage/StorageAdaptor.java b/agent/src/com/cloud/agent/storage/StorageAdaptor.java new file mode 100644 index 00000000000..e5ed91918fe --- /dev/null +++ b/agent/src/com/cloud/agent/storage/StorageAdaptor.java @@ -0,0 +1,25 @@ +package com.cloud.agent.storage; + +import java.util.List; + +import com.cloud.agent.storage.KVMPhysicalDisk.PhysicalDiskFormat; +import com.cloud.storage.Storage.StoragePoolType; + +public interface StorageAdaptor { + + public KVMStoragePool getStoragePool(String uuid); + public KVMPhysicalDisk getPhysicalDisk(String volumeUuid, KVMStoragePool pool); + public KVMStoragePool createStoragePool(String name, String host, String path, StoragePoolType type); + public boolean deleteStoragePool(String uuid); + public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, PhysicalDiskFormat format, long size); + public boolean deletePhysicalDisk(String uuid, KVMStoragePool pool); + public KVMPhysicalDisk createDiskFromTemplate(KVMPhysicalDisk template, String name, PhysicalDiskFormat format, long size, KVMStoragePool destPool); + public KVMPhysicalDisk createTemplateFromDisk(KVMPhysicalDisk disk, String name, PhysicalDiskFormat format, long size, KVMStoragePool destPool); + public List listPhysicalDisks(String storagePoolUuid, KVMStoragePool pool); + public KVMPhysicalDisk copyPhysicalDisk(KVMPhysicalDisk disk, String name, KVMStoragePool destPools); + public KVMPhysicalDisk createDiskFromSnapshot(KVMPhysicalDisk snapshot, String snapshotName, String name, KVMStoragePool destPool); + public KVMStoragePool getStoragePoolByUri(String uri); + public KVMPhysicalDisk getPhysicalDiskFromURI(String uri); + boolean refresh(KVMStoragePool pool); + +} diff --git a/api/src/com/cloud/storage/Storage.java b/api/src/com/cloud/storage/Storage.java index 9856a77e92c..a974cb7d5ae 100755 --- a/api/src/com/cloud/storage/Storage.java +++ b/api/src/com/cloud/storage/Storage.java @@ -97,6 +97,7 @@ public class Storage { Iscsi(true), //for e.g., ZFS Comstar ISO(false), // for iso image LVM(false), // XenServer local LVM SR + CLVM(true), SharedMountPoint(true), VMFS(true), // VMware VMFS storage PreSetup(true), // for XenServer, Storage Pool is set up by customers.