mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
bug 10330: refactor storage code befor merge clvm code
This commit is contained in:
parent
2bfcb3e27b
commit
dd6ed6b108
@ -82,6 +82,9 @@ import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
|
|||||||
import com.cloud.agent.api.CreateStoragePoolCommand;
|
import com.cloud.agent.api.CreateStoragePoolCommand;
|
||||||
import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer;
|
import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer;
|
||||||
import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
|
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.DeleteStoragePoolCommand;
|
||||||
import com.cloud.agent.api.FenceAnswer;
|
import com.cloud.agent.api.FenceAnswer;
|
||||||
import com.cloud.agent.api.FenceCommand;
|
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.SerialDef;
|
||||||
import com.cloud.agent.resource.computing.LibvirtVMDef.TermPolicy;
|
import com.cloud.agent.resource.computing.LibvirtVMDef.TermPolicy;
|
||||||
import com.cloud.agent.resource.virtualnetwork.VirtualRoutingResource;
|
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.dc.Vlan;
|
||||||
import com.cloud.exception.InternalErrorException;
|
import com.cloud.exception.InternalErrorException;
|
||||||
import com.cloud.host.Host.Type;
|
import com.cloud.host.Host.Type;
|
||||||
@ -175,6 +182,7 @@ import com.cloud.resource.ServerResource;
|
|||||||
import com.cloud.resource.ServerResourceBase;
|
import com.cloud.resource.ServerResourceBase;
|
||||||
import com.cloud.storage.Storage;
|
import com.cloud.storage.Storage;
|
||||||
import com.cloud.storage.Storage.ImageFormat;
|
import com.cloud.storage.Storage.ImageFormat;
|
||||||
|
import com.cloud.storage.Storage.StoragePoolType;
|
||||||
import com.cloud.storage.StorageLayer;
|
import com.cloud.storage.StorageLayer;
|
||||||
import com.cloud.storage.Volume;
|
import com.cloud.storage.Volume;
|
||||||
import com.cloud.storage.template.Processor;
|
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 final String _SSHPUBKEYPATH = _SSHKEYSPATH + File.separator + "id_rsa.pub.cloud";
|
||||||
private String _mountPoint = "/mnt";
|
private String _mountPoint = "/mnt";
|
||||||
StorageLayer _storage;
|
StorageLayer _storage;
|
||||||
|
private KVMStoragePoolManager _storagePoolMgr;
|
||||||
|
|
||||||
private static final class KeyValueInterpreter extends OutputInterpreter {
|
private static final class KeyValueInterpreter extends OutputInterpreter {
|
||||||
private final Map<String, String> map = new HashMap<String, String>();
|
private final Map<String, String> map = new HashMap<String, String>();
|
||||||
@ -318,7 +327,6 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
protected List<String> _vmsKilled = new ArrayList<String>();
|
protected List<String> _vmsKilled = new ArrayList<String>();
|
||||||
|
|
||||||
private VirtualRoutingResource _virtRouterResource;
|
private VirtualRoutingResource _virtRouterResource;
|
||||||
protected LibvirtStorageResource _storageResource;
|
|
||||||
|
|
||||||
private String _pingTestPath;
|
private String _pingTestPath;
|
||||||
|
|
||||||
@ -416,6 +424,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Class<?> clazz = Class.forName("com.cloud.storage.JavaStorageLayer");
|
Class<?> clazz = Class.forName("com.cloud.storage.JavaStorageLayer");
|
||||||
_storage = (StorageLayer)ComponentLocator.inject(clazz);
|
_storage = (StorageLayer)ComponentLocator.inject(clazz);
|
||||||
@ -423,6 +433,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
throw new ConfigurationException("Unable to find class " + "com.cloud.storage.JavaStorageLayer");
|
throw new ConfigurationException("Unable to find class " + "com.cloud.storage.JavaStorageLayer");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_storagePoolMgr = new KVMStoragePoolManager(_storage);
|
||||||
|
|
||||||
_virtRouterResource = new VirtualRoutingResource();
|
_virtRouterResource = new VirtualRoutingResource();
|
||||||
|
|
||||||
@ -680,8 +692,6 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
if (_mountPoint == null) {
|
if (_mountPoint == null) {
|
||||||
_mountPoint = "/mnt";
|
_mountPoint = "/mnt";
|
||||||
}
|
}
|
||||||
|
|
||||||
_storageResource = new LibvirtStorageResource(this, _storage, _createvmPath, _timeout, _mountPoint, _monitor);
|
|
||||||
|
|
||||||
saveProperties(params);
|
saveProperties(params);
|
||||||
|
|
||||||
@ -932,47 +942,33 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
String volumePath = cmd.getVolumePath();
|
String volumePath = cmd.getVolumePath();
|
||||||
StorageFilerTO pool = cmd.getPool();
|
StorageFilerTO pool = cmd.getPool();
|
||||||
String secondaryStorageUrl = cmd.getSecondaryStorageURL();
|
String secondaryStorageUrl = cmd.getSecondaryStorageURL();
|
||||||
StoragePool primaryPool = null;
|
try {
|
||||||
Connect conn;
|
KVMStoragePool primaryPool = _storagePoolMgr.getStoragePool(pool.getUuid());
|
||||||
try {
|
String volumeName = UUID.randomUUID().toString();
|
||||||
conn = LibvirtConnection.getConnection();
|
|
||||||
primaryPool = _storageResource.getStoragePool(conn, pool.getUuid());
|
if (copyToSecondary) {
|
||||||
LibvirtStoragePoolDef primary = _storageResource.getStoragePoolDef(conn, primaryPool);
|
KVMPhysicalDisk volume = primaryPool.getPhysicalDisk(cmd.getVolumePath());
|
||||||
String primaryMountPath = primary.getTargetPath();
|
String volumeDestPath = "/volumes/" + cmd.getVolumeId() + File.separator;
|
||||||
|
KVMStoragePool secondaryStoragePool = _storagePoolMgr.getStoragePoolByURI(secondaryStorageUrl + volumeDestPath);
|
||||||
StoragePool secondaryStoragePool = _storageResource.getStoragePoolbyURI(conn, new URI(secondaryStorageUrl));
|
_storagePoolMgr.copyPhysicalDisk(volume, volumeName, secondaryStoragePool);
|
||||||
LibvirtStoragePoolDef spd = _storageResource.getStoragePoolDef(conn, secondaryStoragePool);
|
return new CopyVolumeAnswer(cmd, true, null, null, volumeName);
|
||||||
String ssPmountPath = spd.getTargetPath();
|
} else {
|
||||||
|
volumePath = "/volumes/" + cmd.getVolumeId() + File.separator + volumePath;
|
||||||
String volumeName = UUID.randomUUID().toString();
|
KVMStoragePool secondaryStoragePool = _storagePoolMgr.getStoragePoolByURI(secondaryStorageUrl + volumePath);
|
||||||
|
KVMPhysicalDisk volume = secondaryStoragePool.getPhysicalDisk(cmd.getVolumePath());
|
||||||
if (copyToSecondary) {
|
_storagePoolMgr.copyPhysicalDisk(volume, volumeName, primaryPool);
|
||||||
StorageVol volume = _storageResource.getVolume(conn, primaryPool, volumePath);
|
return new CopyVolumeAnswer(cmd, true, null, null, volumeName);
|
||||||
String volumeDestPath = ssPmountPath + File.separator + "volumes/" + cmd.getVolumeId() + File.separator;
|
}
|
||||||
_storageResource.copyVolume(volumePath, volumeDestPath, volumeName, _cmdsTimeout);
|
} catch (CloudRuntimeException e) {
|
||||||
return new CopyVolumeAnswer(cmd, true, null, null, volumeName);
|
return new CopyVolumeAnswer(cmd, false, e.toString(), null, null);
|
||||||
} 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Answer execute(DeleteStoragePoolCommand cmd) {
|
protected Answer execute(DeleteStoragePoolCommand cmd) {
|
||||||
try {
|
try {
|
||||||
Connect conn = LibvirtConnection.getConnection();
|
_storagePoolMgr.deleteStoragePool(cmd.getPool().getUuid());
|
||||||
_storageResource.deleteStoragePool(conn, cmd.getPool());
|
|
||||||
return new Answer(cmd);
|
return new Answer(cmd);
|
||||||
} catch (LibvirtException e) {
|
} catch (CloudRuntimeException e) {
|
||||||
return new Answer(cmd, false, e.toString());
|
return new Answer(cmd, false, e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1006,48 +1002,32 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
protected Answer execute(CreateCommand cmd) {
|
protected Answer execute(CreateCommand cmd) {
|
||||||
StorageFilerTO pool = cmd.getPool();
|
StorageFilerTO pool = cmd.getPool();
|
||||||
DiskProfile dskch = cmd.getDiskCharacteristics();
|
DiskProfile dskch = cmd.getDiskCharacteristics();
|
||||||
StorageVol tmplVol = null;
|
KVMPhysicalDisk BaseVol = null;
|
||||||
StoragePool primaryPool = null;
|
KVMStoragePool primaryPool = null;
|
||||||
StorageVol vol = null;
|
KVMPhysicalDisk vol = null;
|
||||||
long disksize;
|
long disksize;
|
||||||
try {
|
try {
|
||||||
Connect conn = LibvirtConnection.getConnection();
|
primaryPool = _storagePoolMgr.getStoragePool(pool.getUuid());
|
||||||
primaryPool = _storageResource.getStoragePool(conn, pool.getUuid());
|
|
||||||
|
|
||||||
if (cmd.getTemplateUrl() != null) {
|
if (cmd.getTemplateUrl() != null) {
|
||||||
tmplVol = _storageResource.getVolume(conn, primaryPool, cmd.getTemplateUrl());
|
|
||||||
|
BaseVol = primaryPool.getPhysicalDisk(cmd.getTemplateUrl());
|
||||||
vol = _storageResource.createVolumeFromTempl(primaryPool, tmplVol);
|
vol = _storagePoolMgr.createDiskFromTemplate(BaseVol, UUID.randomUUID().toString(), primaryPool);
|
||||||
|
|
||||||
if (vol == null) {
|
if (vol == null) {
|
||||||
return new Answer(cmd, false, " Can't create storage volume on storage pool");
|
return new Answer(cmd, false, " Can't create storage volume on storage pool");
|
||||||
}
|
}
|
||||||
disksize = tmplVol.getInfo().capacity;
|
disksize = vol.getSize();
|
||||||
} else {
|
} else {
|
||||||
disksize = dskch.getSize();
|
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(),
|
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);
|
return new CreateAnswer(cmd, volume);
|
||||||
} catch (LibvirtException e) {
|
} catch (CloudRuntimeException e) {
|
||||||
|
|
||||||
s_logger.debug("Failed to create volume: " + e.toString());
|
s_logger.debug("Failed to create volume: " + e.toString());
|
||||||
return new CreateAnswer(cmd, e);
|
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();
|
VolumeTO vol = cmd.getVolume();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Connect conn = LibvirtConnection.getConnection();
|
KVMStoragePool pool = _storagePoolMgr.getStoragePool(vol.getPoolUuid());
|
||||||
StoragePool pool = _storageResource.getStoragePool(conn, vol.getPoolUuid());
|
pool.deletePhysicalDisk(vol.getName());
|
||||||
StorageVol volume = _storageResource.getVolume(conn, pool, vol.getPath());
|
|
||||||
volume.delete(0);
|
|
||||||
volume.free();
|
|
||||||
return new Answer(cmd, true, "Success");
|
return new Answer(cmd, true, "Success");
|
||||||
} catch (LibvirtException e) {
|
} catch (CloudRuntimeException e) {
|
||||||
s_logger.debug("Failed to delete volume: " + e.toString());
|
s_logger.debug("Failed to delete volume: " + e.toString());
|
||||||
return new Answer(cmd, false, 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();
|
String vmUuid = vm.getUUIDString();
|
||||||
Object[] args = new Object[] {snapshotName, vmUuid};
|
Object[] args = new Object[] {snapshotName, vmUuid};
|
||||||
String snapshot = SnapshotXML.format(args);
|
String snapshot = SnapshotXML.format(args);
|
||||||
@ -1220,13 +1199,17 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
String snapshotName = cmd.getSnapshotName();
|
String snapshotName = cmd.getSnapshotName();
|
||||||
String snapshotPath = cmd.getVolumePath();
|
String snapshotPath = cmd.getVolumePath();
|
||||||
String snapshotDestPath = null;
|
String snapshotDestPath = null;
|
||||||
|
String snapshotRelPath = null;
|
||||||
String vmName = cmd.getVmName();
|
String vmName = cmd.getVmName();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Connect conn = LibvirtConnection.getConnection();
|
Connect conn = LibvirtConnection.getConnection();
|
||||||
StoragePool secondaryStoragePool = _storageResource.getStoragePoolbyURI(conn, new URI(secondaryStoragePoolUrl));
|
|
||||||
LibvirtStoragePoolDef spd = _storageResource.getStoragePoolDef(conn, secondaryStoragePool);
|
KVMStoragePool secondaryStoragePool = _storagePoolMgr.getStoragePoolByURI(secondaryStoragePoolUrl);
|
||||||
String ssPmountPath = spd.getTargetPath();
|
|
||||||
|
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;
|
snapshotDestPath = ssPmountPath + File.separator + "snapshots" + File.separator + dcId + File.separator + accountId + File.separator + volumeId;
|
||||||
Script command = new Script(_manageSnapshotPath, _cmdsTimeout, s_logger);
|
Script command = new Script(_manageSnapshotPath, _cmdsTimeout, s_logger);
|
||||||
command.add("-b", snapshotPath);
|
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();
|
String vmUuid = vm.getUUIDString();
|
||||||
Object[] args = new Object[] {snapshotName, vmUuid};
|
Object[] args = new Object[] {snapshotName, vmUuid};
|
||||||
String snapshot = SnapshotXML.format(args);
|
String snapshot = SnapshotXML.format(args);
|
||||||
@ -1277,38 +1261,73 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
}
|
}
|
||||||
} catch (LibvirtException e) {
|
} catch (LibvirtException e) {
|
||||||
return new BackupSnapshotAnswer(cmd, false, e.toString(), null, true);
|
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, 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) {
|
protected CreateVolumeFromSnapshotAnswer execute(final CreateVolumeFromSnapshotCommand cmd) {
|
||||||
try {
|
try {
|
||||||
Connect conn = LibvirtConnection.getConnection();
|
|
||||||
/*Make sure secondary storage is mounted*/
|
|
||||||
_storageResource.getStoragePoolbyURI(conn, new URI(cmd.getSecondaryStorageUrl()));
|
|
||||||
|
|
||||||
String snapshotPath = cmd.getSnapshotUuid();
|
String snapshotPath = cmd.getSnapshotUuid();
|
||||||
String primaryUuid = cmd.getPrimaryStoragePoolNameLabel();
|
int index = snapshotPath.lastIndexOf("/");
|
||||||
StoragePool primaryPool = _storageResource.getStoragePool(conn, primaryUuid);
|
snapshotPath = snapshotPath.substring(0, index);
|
||||||
LibvirtStoragePoolDef spd = _storageResource.getStoragePoolDef(conn, primaryPool);
|
KVMStoragePool secondaryPool = _storagePoolMgr.getStoragePoolByURI(cmd.getSecondaryStorageUrl() + snapshotPath);
|
||||||
String primaryPath = spd.getTargetPath();
|
KVMPhysicalDisk snapshot = secondaryPool.getPhysicalDisk(cmd.getSnapshotName());
|
||||||
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 {
|
|
||||||
|
|
||||||
}
|
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 snapshotPath = cmd.getSnapshotUuid();
|
||||||
String tmplName = UUID.randomUUID().toString();
|
String tmplName = UUID.randomUUID().toString();
|
||||||
String tmplFileName = tmplName + ".qcow2";
|
String tmplFileName = tmplName + ".qcow2";
|
||||||
StoragePool secondaryPool;
|
KVMStoragePool secondaryPool;
|
||||||
try {
|
try {
|
||||||
Connect conn = LibvirtConnection.getConnection();
|
|
||||||
secondaryPool = _storageResource.getStoragePoolbyURI(conn, new URI(cmd.getSecondaryStorageUrl()));
|
|
||||||
LibvirtStoragePoolDef spd = _storageResource.getStoragePoolDef(conn, secondaryPool);
|
secondaryPool = _storagePoolMgr.getStoragePoolByURI(cmd.getSecondaryStorageUrl());
|
||||||
String templatePath = spd.getTargetPath() + File.separator + templateInstallFolder;
|
|
||||||
|
String templatePath = secondaryPool.getLocalPath() + File.separator + templateInstallFolder;
|
||||||
|
|
||||||
_storage.mkdirs(templatePath);
|
_storage.mkdirs(templatePath);
|
||||||
|
|
||||||
String tmplPath = templateInstallFolder + File.separator + tmplFileName;
|
String tmplPath = templateInstallFolder + File.separator + tmplFileName;
|
||||||
@ -1350,47 +1371,23 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
loc.save();
|
loc.save();
|
||||||
|
|
||||||
return new CreatePrivateTemplateAnswer(cmd, true, "", tmplPath, info.virtualSize, info.size, tmplName, info.format);
|
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) {
|
} catch (ConfigurationException e) {
|
||||||
return new CreatePrivateTemplateAnswer(cmd, false, e.getMessage());
|
return new CreatePrivateTemplateAnswer(cmd, false, e.getMessage());
|
||||||
} catch (InternalErrorException e) {
|
} catch (InternalErrorException e) {
|
||||||
return new CreatePrivateTemplateAnswer(cmd, false, e.getMessage());
|
return new CreatePrivateTemplateAnswer(cmd, false, e.getMessage());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return new CreatePrivateTemplateAnswer(cmd, false, e.getMessage());
|
return new CreatePrivateTemplateAnswer(cmd, false, e.getMessage());
|
||||||
}
|
} catch (CloudRuntimeException e) {
|
||||||
|
return new CreatePrivateTemplateAnswer(cmd, false, e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected GetStorageStatsAnswer execute(final GetStorageStatsCommand cmd) {
|
protected GetStorageStatsAnswer execute(final GetStorageStatsCommand cmd) {
|
||||||
StoragePool sp = null;
|
|
||||||
try {
|
try {
|
||||||
Connect conn = LibvirtConnection.getConnection();
|
KVMStoragePool sp = _storagePoolMgr.getStoragePool(cmd.getStorageId());
|
||||||
sp = _storageResource.getStoragePool(conn, cmd.getStorageId());
|
return new GetStorageStatsAnswer(cmd, sp.getCapacity(), sp.getUsed());
|
||||||
LibvirtStoragePoolDef spd = _storageResource.getStoragePoolDef(conn, sp);
|
} catch (CloudRuntimeException e) {
|
||||||
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) {
|
|
||||||
return new GetStorageStatsAnswer(cmd, e.toString());
|
return new GetStorageStatsAnswer(cmd, e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1398,18 +1395,18 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
protected CreatePrivateTemplateAnswer execute(CreatePrivateTemplateFromVolumeCommand cmd) {
|
protected CreatePrivateTemplateAnswer execute(CreatePrivateTemplateFromVolumeCommand cmd) {
|
||||||
String secondaryStorageURL = cmd.getSecondaryStorageUrl();
|
String secondaryStorageURL = cmd.getSecondaryStorageUrl();
|
||||||
|
|
||||||
StoragePool secondaryStorage = null;
|
KVMStoragePool secondaryStorage = null;
|
||||||
try {
|
try {
|
||||||
Connect conn = LibvirtConnection.getConnection();
|
Connect conn = LibvirtConnection.getConnection();
|
||||||
String templateFolder = cmd.getAccountId() + File.separator + cmd.getTemplateId() + File.separator;
|
String templateFolder = cmd.getAccountId() + File.separator + cmd.getTemplateId() + File.separator;
|
||||||
String templateInstallFolder = "/template/tmpl/" + templateFolder;
|
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);
|
_storage.mkdirs(tmpltPath);
|
||||||
|
|
||||||
Script command = new Script(_createTmplPath, _timeout, s_logger);
|
Script command = new Script(_createTmplPath, _timeout, s_logger);
|
||||||
command.add("-f", cmd.getVolumePath());
|
command.add("-f", cmd.getVolumePath());
|
||||||
command.add("-t", tmpltPath);
|
command.add("-t", tmpltPath);
|
||||||
@ -1443,8 +1440,6 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
info.size,
|
info.size,
|
||||||
cmd.getUniqueName(),
|
cmd.getUniqueName(),
|
||||||
ImageFormat.QCOW2);
|
ImageFormat.QCOW2);
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
return new CreatePrivateTemplateAnswer(cmd, false, e.toString());
|
|
||||||
} catch (LibvirtException e) {
|
} catch (LibvirtException e) {
|
||||||
s_logger.debug("Failed to get secondary storage pool: " + e.toString());
|
s_logger.debug("Failed to get secondary storage pool: " + e.toString());
|
||||||
return new CreatePrivateTemplateAnswer(cmd, false, 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());
|
return new CreatePrivateTemplateAnswer(cmd, false, e.toString());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return new CreatePrivateTemplateAnswer(cmd, false, e.toString());
|
return new CreatePrivateTemplateAnswer(cmd, false, e.toString());
|
||||||
|
|
||||||
} catch (ConfigurationException e) {
|
} catch (ConfigurationException e) {
|
||||||
return new CreatePrivateTemplateAnswer(cmd, false, e.toString());
|
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);
|
tmpltname = tmplturl.substring(index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
StoragePool secondaryPool = null;
|
KVMPhysicalDisk tmplVol = null;
|
||||||
StoragePool primaryPool = null;
|
|
||||||
StorageVol tmplVol = null;
|
|
||||||
StorageVol primaryVol = null;
|
|
||||||
Connect conn = null;
|
|
||||||
try {
|
try {
|
||||||
conn = LibvirtConnection.getConnection();
|
KVMStoragePool secondaryPool = _storagePoolMgr.getStoragePoolByURI(mountpoint);
|
||||||
secondaryPool = _storageResource.getStoragePoolbyURI(conn, new URI(mountpoint));
|
|
||||||
|
|
||||||
/*Get template vol*/
|
/*Get template vol*/
|
||||||
if (tmpltname == null) {
|
if (tmpltname == null) {
|
||||||
/*Hack: server just pass the directory of system vm template, need to scan the folder */
|
secondaryPool.refresh();
|
||||||
_storageResource.storagePoolRefresh(secondaryPool);
|
List<KVMPhysicalDisk> disks = secondaryPool.listPhysicalDisks();
|
||||||
String[] volumes = secondaryPool.listVolumes();
|
if (disks == null || disks.isEmpty()) {
|
||||||
if (volumes == null) {
|
return new PrimaryStorageDownloadAnswer("Failed to get volumes from pool: " + secondaryPool.getUuid());
|
||||||
return new PrimaryStorageDownloadAnswer("Failed to get volumes from pool: " + secondaryPool.getName());
|
|
||||||
}
|
}
|
||||||
for (String volumeName : volumes) {
|
for (KVMPhysicalDisk disk : disks) {
|
||||||
if (volumeName.endsWith("qcow2")) {
|
if (disk.getName().endsWith("qcow2")) {
|
||||||
tmpltname = volumeName;
|
tmplVol = disk;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tmpltname == null) {
|
if (tmplVol == null) {
|
||||||
return new PrimaryStorageDownloadAnswer("Failed to get template from pool: " + secondaryPool.getName());
|
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*/
|
/*Copy volume to primary storage*/
|
||||||
primaryPool = _storageResource.getStoragePool(conn, cmd.getPoolUuid());
|
KVMStoragePool primaryPool = _storagePoolMgr.getStoragePool(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);
|
|
||||||
|
|
||||||
StorageVolInfo priVolInfo = primaryVol.getInfo();
|
KVMPhysicalDisk primaryVol = _storagePoolMgr.copyPhysicalDisk(tmplVol, UUID.randomUUID().toString(), primaryPool);
|
||||||
return new PrimaryStorageDownloadAnswer(primaryVol.getKey(), priVolInfo.allocation);
|
|
||||||
} catch (LibvirtException e) {
|
return new PrimaryStorageDownloadAnswer(primaryVol.getName(), primaryVol.getSize());
|
||||||
s_logger.debug(e.toString());
|
} catch (CloudRuntimeException e) {
|
||||||
return new PrimaryStorageDownloadAnswer(e.toString());
|
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) {
|
protected Answer execute(CreateStoragePoolCommand cmd) {
|
||||||
@ -1538,29 +1502,18 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected Answer execute(ModifyStoragePoolCommand cmd) {
|
protected Answer execute(ModifyStoragePoolCommand cmd) {
|
||||||
try {
|
KVMStoragePool storagepool = _storagePoolMgr.createStoragePool(cmd.getPool().getUuid(), cmd.getPool().getHost(), cmd.getPool().getPath(), cmd.getPool().getType());
|
||||||
Connect conn = LibvirtConnection.getConnection();
|
if (storagepool == null) {
|
||||||
StoragePool storagePool = _storageResource.getStoragePool(conn, cmd.getPool());
|
return new Answer(cmd, false, " Failed to create storage pool");
|
||||||
if (storagePool == null) {
|
|
||||||
return new Answer(cmd, false, " Failed to create storage pool");
|
|
||||||
}
|
|
||||||
|
|
||||||
StoragePoolInfo spi = null;
|
|
||||||
|
|
||||||
spi = storagePool.getInfo();
|
|
||||||
|
|
||||||
Map<String, TemplateInfo> tInfo = new HashMap<String, TemplateInfo>();
|
|
||||||
ModifyStoragePoolAnswer answer = new ModifyStoragePoolAnswer(cmd,
|
|
||||||
spi.capacity,
|
|
||||||
spi.allocation,
|
|
||||||
tInfo);
|
|
||||||
|
|
||||||
storagePool.free();
|
|
||||||
return answer;
|
|
||||||
} catch (LibvirtException e) {
|
|
||||||
return new Answer(cmd, false, e.getMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, TemplateInfo> tInfo = new HashMap<String, TemplateInfo>();
|
||||||
|
ModifyStoragePoolAnswer answer = new ModifyStoragePoolAnswer(cmd,
|
||||||
|
storagepool.getCapacity(),
|
||||||
|
storagepool.getUsed(),
|
||||||
|
tInfo);
|
||||||
|
|
||||||
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Answer execute(SecurityIngressRulesCmd cmd) {
|
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 {
|
private String getVolumePath(Connect conn, VolumeTO volume) throws LibvirtException, URISyntaxException {
|
||||||
if (volume.getType() == Volume.Type.ISO && volume.getPath() != null) {
|
if (volume.getType() == Volume.Type.ISO && volume.getPath() != null) {
|
||||||
StorageVol vol = _storageResource.getVolumeFromURI(conn, volume.getPath());
|
String isoPath = volume.getPath();
|
||||||
return vol.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 {
|
} else {
|
||||||
return volume.getPath();
|
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{
|
protected void createVbd(Connect conn, VirtualMachineTO vmSpec, String vmName, LibvirtVMDef vm) throws InternalErrorException, LibvirtException, URISyntaxException{
|
||||||
for (VolumeTO volume : vmSpec.getDisks()) {
|
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.diskBus diskBusType = getGuestDiskModel(vmSpec.getOs());
|
||||||
DiskDef disk = new DiskDef();
|
DiskDef disk = new DiskDef();
|
||||||
@ -2283,8 +2255,11 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int devId = (int)volume.getDeviceId();
|
int devId = (int)volume.getDeviceId();
|
||||||
|
if (pool.getType() == StoragePoolType.CLVM) {
|
||||||
disk.defFileBasedDisk(volume.getPath(), devId, diskBusType, DiskDef.diskFmtType.QCOW2);
|
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.
|
//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<DiskDef> disks = vm.getDevices().getDisks();
|
List<DiskDef> disks = vm.getDevices().getDisks();
|
||||||
DiskDef rootDisk = disks.get(0);
|
DiskDef rootDisk = disks.get(0);
|
||||||
VolumeTO rootVol = getVolume(vmSpec, Volume.Type.ROOT);
|
VolumeTO rootVol = getVolume(vmSpec, Volume.Type.ROOT);
|
||||||
StoragePool pool = _storageResource.getStoragePool(conn, rootVol.getPoolUuid());
|
KVMStoragePool pool = _storagePoolMgr.getStoragePool(rootVol.getPoolUuid());
|
||||||
StorageVol tmplVol = _storageResource.createTmplDataDisk(conn, pool, 10L * 1024 * 1024);
|
KVMPhysicalDisk disk = pool.createPhysicalDisk(UUID.randomUUID().toString(), KVMPhysicalDisk.PhysicalDiskFormat.RAW, 10L * 1024 * 1024);
|
||||||
String datadiskPath = tmplVol.getKey();
|
/*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*/
|
/*add patch disk*/
|
||||||
DiskDef patchDisk = new DiskDef();
|
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);
|
disks.add(patchDisk);
|
||||||
patchDisk.setDiskPath(datadiskPath);
|
|
||||||
|
|
||||||
String bootArgs = vmSpec.getBootArgs();
|
String bootArgs = vmSpec.getBootArgs();
|
||||||
|
|
||||||
patchSystemVm(bootArgs, datadiskPath, vmName);
|
patchSystemVm(bootArgs, datadiskPath, vmName);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String createVlanBr(String vlanId, String nic) throws InternalErrorException{
|
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 {
|
protected synchronized String attachOrDetachISO(Connect conn, String vmName, String isoPath, boolean isAttach) throws LibvirtException, URISyntaxException, InternalErrorException {
|
||||||
String isoXml = null;
|
String isoXml = null;
|
||||||
if (isoPath != null && isAttach) {
|
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();
|
isoPath = isoVol.getPath();
|
||||||
|
|
||||||
DiskDef iso = new DiskDef();
|
DiskDef iso = new DiskDef();
|
||||||
@ -2548,14 +2537,16 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
|
|
||||||
StartupStorageCommand sscmd = null;
|
StartupStorageCommand sscmd = null;
|
||||||
try {
|
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 = new StartupStorageCommand();
|
||||||
sscmd.setPoolInfo(pi);
|
sscmd.setPoolInfo(pi);
|
||||||
sscmd.setGuid(pi.getUuid());
|
sscmd.setGuid(pi.getUuid());
|
||||||
sscmd.setDataCenter(_dcId);
|
sscmd.setDataCenter(_dcId);
|
||||||
sscmd.setResourceType(Storage.StorageResourceType.STORAGE_POOL);
|
sscmd.setResourceType(Storage.StorageResourceType.STORAGE_POOL);
|
||||||
} catch (LibvirtException e) {
|
} catch (CloudRuntimeException e) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,6 +22,8 @@ import org.apache.log4j.Logger;
|
|||||||
import org.libvirt.Connect;
|
import org.libvirt.Connect;
|
||||||
import org.libvirt.LibvirtException;
|
import org.libvirt.LibvirtException;
|
||||||
|
|
||||||
|
import com.cloud.agent.kvm.KVMConnection;
|
||||||
|
|
||||||
public class LibvirtConnection {
|
public class LibvirtConnection {
|
||||||
private static final Logger s_logger = Logger.getLogger(LibvirtConnection.class);
|
private static final Logger s_logger = Logger.getLogger(LibvirtConnection.class);
|
||||||
static private Connect _connection;
|
static private Connect _connection;
|
||||||
|
|||||||
@ -22,6 +22,7 @@ public class LibvirtStoragePoolDef {
|
|||||||
public enum poolType {
|
public enum poolType {
|
||||||
ISCSI("iscsi"),
|
ISCSI("iscsi"),
|
||||||
NETFS("netfs"),
|
NETFS("netfs"),
|
||||||
|
LOGICAL("logical"),
|
||||||
DIR("dir");
|
DIR("dir");
|
||||||
String _poolType;
|
String _poolType;
|
||||||
poolType(String poolType) {
|
poolType(String poolType) {
|
||||||
|
|||||||
@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
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<String, Object> _storagePools = new ConcurrentHashMap<String, Object>();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -46,6 +46,9 @@ public class LibvirtStorageVolumeDef {
|
|||||||
_backingFormat = tmplFormat;
|
_backingFormat = tmplFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public volFormat getFormat() {
|
||||||
|
return this._volFormat;
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder storageVolBuilder = new StringBuilder();
|
StringBuilder storageVolBuilder = new StringBuilder();
|
||||||
|
|||||||
@ -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 = "<pool type='dir'>" +
|
||||||
|
"<name>test</name>" +
|
||||||
|
"<uuid>bf723c83-4b95-259c-7089-60776e61a11f</uuid>" +
|
||||||
|
"<capacity>20314165248</capacity>" +
|
||||||
|
"<allocation>1955450880</allocation>" +
|
||||||
|
"<available>18358714368</available>" +
|
||||||
|
"<source>" +
|
||||||
|
"<host name='nfs1.lab.vmops.com'/>" +
|
||||||
|
"<dir path='/export/home/edison/kvm/primary'/>" +
|
||||||
|
"<format type='auto'/>" +
|
||||||
|
"</source>" +
|
||||||
|
"<target>" +
|
||||||
|
"<path>/media</path>" +
|
||||||
|
"<permissions>" +
|
||||||
|
"<mode>0700</mode>" +
|
||||||
|
"<owner>0</owner>" +
|
||||||
|
"<group>0</group>" +
|
||||||
|
"</permissions>" +
|
||||||
|
"</target>" +
|
||||||
|
"</pool>";
|
||||||
|
|
||||||
|
LibvirtStoragePoolXMLParser parser = new LibvirtStoragePoolXMLParser();
|
||||||
|
LibvirtStoragePoolDef pool = parser.parseStoragePoolXML(storagePool);
|
||||||
|
s_logger.debug(pool.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -337,11 +337,12 @@ public class LibvirtVMDef {
|
|||||||
_diskFmtType = diskFmtType.RAW;
|
_diskFmtType = diskFmtType.RAW;
|
||||||
_bus = diskBus.IDE;
|
_bus = diskBus.IDE;
|
||||||
}
|
}
|
||||||
public void defBlockBasedDisk(String diskName, String diskLabel, diskBus bus) {
|
public void defBlockBasedDisk(String diskName, int devId, diskBus bus) {
|
||||||
_diskType = diskType.BLOCK;
|
_diskType = diskType.BLOCK;
|
||||||
_deviceType = deviceType.DISK;
|
_deviceType = deviceType.DISK;
|
||||||
|
_diskFmtType = diskFmtType.RAW;
|
||||||
_sourcePath = diskName;
|
_sourcePath = diskName;
|
||||||
_diskLabel = diskLabel;
|
_diskLabel = getDevLabel(devId, bus);
|
||||||
_bus = bus;
|
_bus = bus;
|
||||||
}
|
}
|
||||||
public void setReadonly() {
|
public void setReadonly() {
|
||||||
|
|||||||
56
agent/src/com/cloud/agent/storage/KVMPhysicalDisk.java
Normal file
56
agent/src/com/cloud/agent/storage/KVMPhysicalDisk.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
21
agent/src/com/cloud/agent/storage/KVMStoragePool.java
Normal file
21
agent/src/com/cloud/agent/storage/KVMStoragePool.java
Normal file
@ -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<KVMPhysicalDisk> listPhysicalDisks();
|
||||||
|
public String getUuid();
|
||||||
|
public long getCapacity();
|
||||||
|
public long getUsed();
|
||||||
|
public boolean refresh();
|
||||||
|
public boolean isExternalSnapshot();
|
||||||
|
public String getLocalPath();
|
||||||
|
public StoragePoolType getType();
|
||||||
|
}
|
||||||
77
agent/src/com/cloud/agent/storage/KVMStoragePoolManager.java
Normal file
77
agent/src/com/cloud/agent/storage/KVMStoragePoolManager.java
Normal file
@ -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<String, Object> _storagePools = new ConcurrentHashMap<String, Object>();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
6
agent/src/com/cloud/agent/storage/KVMVirtualDisk.java
Normal file
6
agent/src/com/cloud/agent/storage/KVMVirtualDisk.java
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package com.cloud.agent.storage;
|
||||||
|
|
||||||
|
public class KVMVirtualDisk {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
630
agent/src/com/cloud/agent/storage/LibvirtStorageAdaptor.java
Normal file
630
agent/src/com/cloud/agent/storage/LibvirtStorageAdaptor.java
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<KVMPhysicalDisk> listPhysicalDisks(String storagePoolUuid, KVMStoragePool pool) {
|
||||||
|
LibvirtStoragePool libvirtPool = (LibvirtStoragePool)pool;
|
||||||
|
StoragePool virtPool = libvirtPool.getPool();
|
||||||
|
List<KVMPhysicalDisk> disks = new ArrayList<KVMPhysicalDisk>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
131
agent/src/com/cloud/agent/storage/LibvirtStoragePool.java
Normal file
131
agent/src/com/cloud/agent/storage/LibvirtStoragePool.java
Normal file
@ -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<KVMPhysicalDisk> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
25
agent/src/com/cloud/agent/storage/StorageAdaptor.java
Normal file
25
agent/src/com/cloud/agent/storage/StorageAdaptor.java
Normal file
@ -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<KVMPhysicalDisk> 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);
|
||||||
|
|
||||||
|
}
|
||||||
@ -97,6 +97,7 @@ public class Storage {
|
|||||||
Iscsi(true), //for e.g., ZFS Comstar
|
Iscsi(true), //for e.g., ZFS Comstar
|
||||||
ISO(false), // for iso image
|
ISO(false), // for iso image
|
||||||
LVM(false), // XenServer local LVM SR
|
LVM(false), // XenServer local LVM SR
|
||||||
|
CLVM(true),
|
||||||
SharedMountPoint(true),
|
SharedMountPoint(true),
|
||||||
VMFS(true), // VMware VMFS storage
|
VMFS(true), // VMware VMFS storage
|
||||||
PreSetup(true), // for XenServer, Storage Pool is set up by customers.
|
PreSetup(true), // for XenServer, Storage Pool is set up by customers.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user