CLOUDSTACK-4810: Enable hypervisor snapshots for CloudStack-managed storage (for XenServer and VMware)

This commit is contained in:
Mike Tutkowski 2013-12-16 22:39:14 -07:00
parent 497feab841
commit 0ddbae580e
7 changed files with 141 additions and 179 deletions

View File

@ -4818,13 +4818,10 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
auth.setChapName(chapName);
auth.setChapSecret(chapSecret);
if (StringUtils.isNotBlank(mutualChapName) &&
StringUtils.isNotBlank(mutualChapSecret)) {
auth.setMutualChapInherited(false);
auth.setMutualChapAuthenticationType(strAuthType);
auth.setMutualChapName(mutualChapName);
auth.setMutualChapSecret(mutualChapSecret);
}
auth.setMutualChapInherited(false);
auth.setMutualChapAuthenticationType(strAuthType);
auth.setMutualChapName(mutualChapName);
auth.setMutualChapSecret(mutualChapSecret);
target.setAuthenticationProperties(auth);

View File

@ -1192,14 +1192,16 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
}
}
protected VBD createVbd(Connection conn, DiskTO volume, String vmName, VM vm, BootloaderType bootLoaderType, VDI vdi) throws XmlRpcException, XenAPIException {
protected VBD createVbd(Connection conn, DiskTO volume, String vmName, VM vm, BootloaderType bootLoaderType) throws XmlRpcException, XenAPIException {
Volume.Type type = volume.getType();
if (vdi == null) {
vdi = mount(conn, vmName, volume);
}
VDI vdi = mount(conn, vmName, volume);
if ( vdi != null ) {
if ("detached".equals(vdi.getNameLabel(conn))) {
vdi.setNameLabel(conn, vmName + "-DATA");
}
Map<String, String> smConfig = vdi.getSmConfig(conn);
for (String key : smConfig.keySet()) {
if (key.startsWith("host_")) {
@ -1684,37 +1686,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
vm = createVmFromTemplate(conn, vmSpec, host);
for (DiskTO disk : vmSpec.getDisks()) {
VDI vdi = null;
if (disk.getData() instanceof VolumeObjectTO) {
Map<String, String> details = disk.getDetails();
boolean isManaged = details != null && Boolean.parseBoolean(details.get(DiskTO.MANAGED));
if (isManaged) {
String iScsiName = details.get(DiskTO.IQN);
String storageHost = details.get(DiskTO.STORAGE_HOST);
String chapInitiatorUsername = disk.getDetails().get(DiskTO.CHAP_INITIATOR_USERNAME);
String chapInitiatorSecret = disk.getDetails().get(DiskTO.CHAP_INITIATOR_SECRET);
Long volumeSize = Long.parseLong(details.get(DiskTO.VOLUME_SIZE));
String vdiNameLabel = vmName + "-DATA";
SR sr = getIscsiSR(conn, iScsiName, storageHost, iScsiName,
chapInitiatorUsername, chapInitiatorSecret, true);
vdi = getVDIbyUuid(conn, disk.getPath(), false);
if (vdi == null) {
vdi = createVdi(sr, vdiNameLabel, volumeSize);
iqnToPath.put(iScsiName, vdi.getUuid(conn));
}
else {
vdi.setNameLabel(conn, vdiNameLabel);
}
}
}
createVbd(conn, disk, vmName, vm, vmSpec.getBootloader(), vdi);
createVbd(conn, disk, vmName, vm, vmSpec.getBootloader());
}
if (vmSpec.getType() != VirtualMachine.Type.User) {
@ -1821,46 +1793,6 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
s_logger.debug("The VM is in stopped state, detected problem during startup : " + vmName);
}
}
if (state != State.Running) {
disconnectManagedVolumes(conn, vm);
}
}
}
private void disconnectManagedVolumes(Connection conn, VM vm) {
try {
Set<VBD> vbds = vm.getVBDs(conn);
for (VBD vbd : vbds) {
VDI vdi = vbd.getVDI(conn);
SR sr = null;
try {
sr = vdi.getSR(conn);
}
catch (Exception ex) {
continue;
}
if (sr.getNameLabel(conn).startsWith("/iqn.")) {
VBD.Record vbdr = vbd.getRecord(conn);
if (vbdr.currentlyAttached) {
vbd.unplug(conn);
}
vbd.destroy(conn);
vdi.setNameLabel(conn, "detached");
umount(conn, vdi);
handleSrAndVdiDetach(sr.getNameLabel(conn));
}
}
} catch (Exception ex) {
s_logger.debug(ex.getMessage());
}
}
@ -4061,8 +3993,6 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
try {
if (vm.getPowerState(conn) == VmPowerState.HALTED) {
disconnectManagedVolumes(conn, vm);
Set<VIF> vifs = vm.getVIFs(conn);
List<Network> networks = new ArrayList<Network>();
for (VIF vif : vifs) {

View File

@ -41,6 +41,7 @@ import com.xensource.xenapi.Pool;
import com.xensource.xenapi.SR;
import com.xensource.xenapi.Types;
import com.xensource.xenapi.Types.BadServerResponse;
import com.xensource.xenapi.Types.VmPowerState;
import com.xensource.xenapi.Types.XenAPIException;
import com.xensource.xenapi.VBD;
import com.xensource.xenapi.VDI;
@ -164,19 +165,39 @@ public class XenServerStorageProcessor implements StorageProcessor {
@Override
public AttachAnswer attachVolume(AttachCommand cmd) {
String vmName = cmd.getVmName();
String vdiNameLabel = vmName + "-DATA";
DiskTO disk = cmd.getDisk();
DataTO data = disk.getData();
try {
Connection conn = hypervisorResource.getConnection();
String vmName = cmd.getVmName();
String vdiNameLabel = vmName + "-DATA";
VDI vdi = null;
Connection conn = this.hypervisorResource.getConnection();
VM vm = null;
boolean vmNotRunning = true;
try {
vm = this.hypervisorResource.getVM(conn, vmName);
VM.Record vmr = vm.getRecord(conn);
vmNotRunning = vmr.powerState != VmPowerState.RUNNING;
}
catch (CloudRuntimeException ex) {
}
Map<String, String> details = cmd.getDisk().getDetails();
boolean isManaged = Boolean.parseBoolean(details.get(DiskTO.MANAGED));
// if the VM is not running and we're not dealing with managed storage, just return success (nothing to do here)
// this should probably never actually happen
if (vmNotRunning && !isManaged) {
return new AttachAnswer(disk);
}
VDI vdi = null;
if (isManaged) {
String iScsiName = details.get(DiskTO.IQN);
String storageHost = details.get(DiskTO.STORAGE_HOST);
@ -184,56 +205,64 @@ public class XenServerStorageProcessor implements StorageProcessor {
String chapInitiatorSecret = disk.getDetails().get(DiskTO.CHAP_INITIATOR_SECRET);
Long volumeSize = Long.parseLong(details.get(DiskTO.VOLUME_SIZE));
SR sr = hypervisorResource.getIscsiSR(conn, iScsiName, storageHost, iScsiName,
chapInitiatorUsername, chapInitiatorSecret, true);
SR sr = this.hypervisorResource.getIscsiSR(conn, iScsiName, storageHost, iScsiName, chapInitiatorUsername, chapInitiatorSecret, true);
vdi = hypervisorResource.getVDIbyUuid(conn, data.getPath(), false);
if (vdi == null) {
vdi = hypervisorResource.createVdi(sr, vdiNameLabel, volumeSize);
}
if (vmNotRunning) {
DiskTO newDisk = new DiskTO(disk.getData(), disk.getDiskSeq(), vdi.getUuid(conn), disk.getType());
return new AttachAnswer(newDisk);
}
}
else {
vdi = hypervisorResource.mount(conn, null, null, data.getPath());
}
// Look up the VM
VM vm = hypervisorResource.getVM(conn, vmName);
/* For HVM guest, if no pv driver installed, no attach/detach */
boolean isHVM;
if (vm.getPVBootloader(conn).equalsIgnoreCase("")) {
isHVM = true;
} else {
isHVM = false;
}
boolean isHVM = vm.getPVBootloader(conn).equalsIgnoreCase("");
VMGuestMetrics vgm = vm.getGuestMetrics(conn);
boolean pvDrvInstalled = false;
if (!hypervisorResource.isRefNull(vgm) && vgm.getPVDriversUpToDate(conn)) {
if (!this.hypervisorResource.isRefNull(vgm) && vgm.getPVDriversUpToDate(conn)) {
pvDrvInstalled = true;
}
if (isHVM && !pvDrvInstalled) {
s_logger.warn(": You attempted an operation on a VM which requires PV drivers to be installed but the drivers were not detected");
return new AttachAnswer("You attempted an operation that requires PV drivers to be installed on the VM. Please install them by inserting xen-pv-drv.iso.");
}
// Figure out the disk number to attach the VM to
String diskNumber = null;
Long deviceId = disk.getDiskSeq();
if( deviceId != null ) {
if( deviceId.longValue() == 3 ) {
if (deviceId != null) {
if (deviceId.longValue() == 3) {
String msg = "Device 3 is reserved for CD-ROM, choose other device";
return new AttachAnswer(msg);
}
if(hypervisorResource.isDeviceUsed(conn, vm, deviceId)) {
if (this.hypervisorResource.isDeviceUsed(conn, vm, deviceId)) {
String msg = "Device " + deviceId + " is used in VM " + vmName;
return new AttachAnswer(msg);
}
diskNumber = deviceId.toString();
} else {
diskNumber = hypervisorResource.getUnusedDeviceNum(conn, vm);
}
// Create a new VBD
VBD.Record vbdr = new VBD.Record();
vbdr.VM = vm;
vbdr.VDI = vdi;
vbdr.bootable = false;
@ -241,6 +270,7 @@ public class XenServerStorageProcessor implements StorageProcessor {
vbdr.mode = Types.VbdMode.RW;
vbdr.type = Types.VbdType.DISK;
vbdr.unpluggable = true;
VBD vbd = VBD.create(conn, vbdr);
// Attach the VBD to the VM
@ -248,9 +278,10 @@ public class XenServerStorageProcessor implements StorageProcessor {
// Update the VDI's label to include the VM name
vdi.setNameLabel(conn, vdiNameLabel);
DiskTO newDisk = new DiskTO(disk.getData(), Long.parseLong(diskNumber), vdi.getUuid(conn), disk.getType());
return new AttachAnswer(newDisk);
DiskTO newDisk = new DiskTO(disk.getData(), Long.parseLong(diskNumber), vdi.getUuid(conn), disk.getType());
return new AttachAnswer(newDisk);
} catch (XenAPIException e) {
String msg = "Failed to attach volume" + " for uuid: " + data.getPath() + " due to " + e.toString();
s_logger.warn(msg, e);
@ -326,55 +357,73 @@ public class XenServerStorageProcessor implements StorageProcessor {
}
}
@Override
public Answer dettachVolume(DettachCommand cmd) {
String vmName = cmd.getVmName();
DiskTO disk = cmd.getDisk();
DataTO data = disk.getData();
try {
Connection conn = hypervisorResource.getConnection();
// Look up the VDI
VDI vdi = hypervisorResource.mount(conn, null, null, data.getPath());
// Look up the VM
VM vm = hypervisorResource.getVM(conn, vmName);
/* For HVM guest, if no pv driver installed, no attach/detach */
boolean isHVM;
if (vm.getPVBootloader(conn).equalsIgnoreCase("")) {
isHVM = true;
} else {
isHVM = false;
Connection conn = this.hypervisorResource.getConnection();
String vmName = cmd.getVmName();
VM vm = null;
boolean vmNotRunning = true;
try {
vm = this.hypervisorResource.getVM(conn, vmName);
VM.Record vmr = vm.getRecord(conn);
vmNotRunning = vmr.powerState != VmPowerState.RUNNING;
}
VMGuestMetrics vgm = vm.getGuestMetrics(conn);
boolean pvDrvInstalled = false;
if (!hypervisorResource.isRefNull(vgm) && vgm.getPVDriversUpToDate(conn)) {
pvDrvInstalled = true;
}
if (isHVM && !pvDrvInstalled) {
s_logger.warn(": You attempted an operation on a VM which requires PV drivers to be installed but the drivers were not detected");
return new DettachAnswer("You attempted an operation that requires PV drivers to be installed on the VM. Please install them by inserting xen-pv-drv.iso.");
catch (CloudRuntimeException ex) {
}
// if the VM is not running and we're not dealing with managed storage, just return success (nothing to do here)
// this should probably never actually happen
if (vmNotRunning && !cmd.isManaged()) {
return new DettachAnswer(disk);
}
// Look up all VBDs for this VDI
Set<VBD> vbds = vdi.getVBDs(conn);
if (!vmNotRunning) {
/* For HVM guest, if no pv driver installed, no attach/detach */
boolean isHVM = vm.getPVBootloader(conn).equalsIgnoreCase("");
// Detach each VBD from its VM, and then destroy it
for (VBD vbd : vbds) {
VBD.Record vbdr = vbd.getRecord(conn);
VMGuestMetrics vgm = vm.getGuestMetrics(conn);
boolean pvDrvInstalled = false;
if (vbdr.currentlyAttached) {
vbd.unplug(conn);
if (!this.hypervisorResource.isRefNull(vgm) && vgm.getPVDriversUpToDate(conn)) {
pvDrvInstalled = true;
}
vbd.destroy(conn);
if (isHVM && !pvDrvInstalled) {
s_logger.warn(": You attempted an operation on a VM which requires PV drivers to be installed but the drivers were not detected");
return new DettachAnswer("You attempted an operation that requires PV drivers to be installed on the VM. Please install them by inserting xen-pv-drv.iso.");
}
VDI vdi = this.hypervisorResource.mount(conn, null, null, data.getPath());
// Look up all VBDs for this VDI
Set<VBD> vbds = vdi.getVBDs(conn);
// Detach each VBD from its VM, and then destroy it
for (VBD vbd : vbds) {
VBD.Record vbdr = vbd.getRecord(conn);
if (vbdr.currentlyAttached) {
vbd.unplug(conn);
}
vbd.destroy(conn);
}
// Update the VDI's label to be "detached"
vdi.setNameLabel(conn, "detached");
this.hypervisorResource.umount(conn, vdi);
}
// Update the VDI's label to be "detached"
vdi.setNameLabel(conn, "detached");
hypervisorResource.umount(conn, vdi);
if (cmd.isManaged()) {
hypervisorResource.handleSrAndVdiDetach(cmd.get_iScsiName());
}
@ -386,7 +435,6 @@ public class XenServerStorageProcessor implements StorageProcessor {
}
}
protected SR getSRByNameLabel(Connection conn, String nameLabel) throws BadServerResponse, XenAPIException, XmlRpcException {
Set<SR> srs = SR.getByNameLabel(conn, nameLabel);
if (srs.size() != 1) {

View File

@ -217,22 +217,13 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
String chapInitiatorSecret = accountDetail.getValue();
StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(volumeInfo.getPoolId(), SolidFireUtil.USE_MUTUAL_CHAP_FOR_VMWARE);
accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_TARGET_USERNAME);
boolean useMutualChapForVMware = new Boolean(storagePoolDetail.getValue());
String chapTargetUsername = accountDetail.getValue();
String chapTargetUsername = null;
String chapTargetSecret = null;
accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_TARGET_SECRET);
if (useMutualChapForVMware) {
accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_TARGET_USERNAME);
chapTargetUsername = accountDetail.getValue();
accountDetail = _accountDetailsDao.findDetail(accountId, SolidFireUtil.CHAP_TARGET_SECRET);
chapTargetSecret = accountDetail.getValue();
}
String chapTargetSecret = accountDetail.getValue();
return new ChapInfoImpl(chapInitiatorUsername, chapInitiatorSecret,
chapTargetUsername, chapTargetSecret);

View File

@ -168,23 +168,6 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
details.put(SolidFireUtil.CLUSTER_DEFAULT_MAX_IOPS, String.valueOf(lClusterDefaultMaxIops));
details.put(SolidFireUtil.CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS, String.valueOf(fClusterDefaultBurstIopsPercentOfMaxIops));
String useMutualChapForVMware = Boolean.TRUE.toString();
try {
useMutualChapForVMware = getValue(SolidFireUtil.USE_MUTUAL_CHAP_FOR_VMWARE, url);
if (useMutualChapForVMware == null || new Boolean(useMutualChapForVMware)) {
useMutualChapForVMware = Boolean.TRUE.toString();
}
else {
useMutualChapForVMware = Boolean.FALSE.toString();
}
}
catch (Exception ex) {
}
details.put(SolidFireUtil.USE_MUTUAL_CHAP_FOR_VMWARE, useMutualChapForVMware);
// this adds a row in the cloud.storage_pool table for this SolidFire cluster
return dataStoreHelper.createPrimaryDataStore(parameters);
}

View File

@ -75,8 +75,6 @@ public class SolidFireUtil
public static final String CHAP_TARGET_USERNAME = "chapTargetUsername";
public static final String CHAP_TARGET_SECRET = "chapTargetSecret";
public static final String USE_MUTUAL_CHAP_FOR_VMWARE = "useMutualChapForVMware";
public static long createSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword,
String strSfVolumeName, long lSfAccountId, long lTotalSize, boolean bEnable512e, final String strCloudStackVolumeSize,
long lMinIops, long lMaxIops, long lBurstIops)

View File

@ -1454,11 +1454,19 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
}
}
StoragePoolVO volumePool = _storagePoolDao.findById(volume.getPoolId());
if (hostId != null) {
HostVO host = _hostDao.findById(hostId);
if (host != null && host.getHypervisorType() == HypervisorType.XenServer && volumePool.isManaged()) {
sendCommand = true;
}
}
Answer answer = null;
if (sendCommand) {
StoragePoolVO volumePool = _storagePoolDao.findById(volume.getPoolId());
DataTO volTO = volFactory.getVolume(volume.getId()).getTO();
DiskTO disk = new DiskTO(volTO, volume.getDeviceId(), volume.getPath(), volume.getVolumeType());
@ -1867,21 +1875,28 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
boolean sendCommand = (vm.getState() == State.Running);
AttachAnswer answer = null;
Long hostId = vm.getHostId();
if (hostId == null) {
hostId = vm.getLastHostId();
HostVO host = _hostDao.findById(hostId);
if (host != null && host.getHypervisorType() == HypervisorType.VMware) {
sendCommand = true;
}
}
StoragePoolVO volumeToAttachStoragePool = null;
HostVO host = null;
StoragePoolVO volumeToAttachStoragePool = _storagePoolDao.findById(volumeToAttach.getPoolId());
if (hostId != null) {
host = _hostDao.findById(hostId);
if (host != null && host.getHypervisorType() == HypervisorType.XenServer && volumeToAttachStoragePool.isManaged()) {
sendCommand = true;
}
}
if (sendCommand) {
volumeToAttachStoragePool = _storagePoolDao.findById(volumeToAttach.getPoolId());
HostVO host = _hostDao.findById(hostId);
if (host.getHypervisorType() == HypervisorType.KVM &&
volumeToAttachStoragePool.isManaged() &&
volumeToAttach.getPath() == null) {