Merge branch '4.8'

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
Rohit Yadav 2016-05-03 08:22:37 +05:30
commit 4d57ec04ac
16 changed files with 214 additions and 38 deletions

2
debian/control vendored
View File

@ -15,7 +15,7 @@ Description: A common package which contains files which are shared by several C
Package: cloudstack-management Package: cloudstack-management
Architecture: all Architecture: all
Depends: ${misc:Depends}, ${python:Depends}, cloudstack-common (= ${source:Version}), tomcat6, sudo, jsvc, python-mysqldb, libmysql-java, augeas-tools, mysql-client, adduser Depends: ${misc:Depends}, ${python:Depends}, cloudstack-common (= ${source:Version}), tomcat6, sudo, jsvc, python-mysqldb, libmysql-java, augeas-tools, mysql-client, adduser, bzip2
Conflicts: cloud-server, cloud-client, cloud-client-ui Conflicts: cloud-server, cloud-client, cloud-client-ui
Description: CloudStack server library Description: CloudStack server library
The CloudStack management server The CloudStack management server

View File

@ -2909,12 +2909,12 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
newServiceOffering.getCpu() + " cpu(s) at " + newServiceOffering.getSpeed() + " Mhz, and " + newServiceOffering.getRamSize() + " MB of memory"); newServiceOffering.getCpu() + " cpu(s) at " + newServiceOffering.getSpeed() + " Mhz, and " + newServiceOffering.getRamSize() + " MB of memory");
} }
// Check that the service offering being upgraded to has storage tags subset of the current service offering storage tags, since volume is not migrated. // Check that the service offering being upgraded to has all the tags of the current service offering.
final List<String> currentTags = StringUtils.csvTagsToList(currentServiceOffering.getTags()); final List<String> currentTags = StringUtils.csvTagsToList(currentServiceOffering.getTags());
final List<String> newTags = StringUtils.csvTagsToList(newServiceOffering.getTags()); final List<String> newTags = StringUtils.csvTagsToList(newServiceOffering.getTags());
if (!currentTags.containsAll(newTags)) { if (!newTags.containsAll(currentTags)) {
throw new InvalidParameterValueException("Unable to upgrade virtual machine; the new service offering " + " should have tags as subset of " + throw new InvalidParameterValueException("Unable to upgrade virtual machine; the current service offering " + " should have tags as subset of " +
"current service offering tags. Current service offering tags: " + currentTags + "; " + "new service " + "offering tags: " + newTags); "the new service offering tags. Current service offering tags: " + currentTags + "; " + "new service " + "offering tags: " + newTags);
} }
} }

View File

@ -30,7 +30,9 @@ import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.ArrayList;
import com.cloud.service.dao.ServiceOfferingDao;
import junit.framework.Assert; import junit.framework.Assert;
import org.junit.Before; import org.junit.Before;
@ -136,6 +138,8 @@ public class VirtualMachineManagerImplTest {
@Mock @Mock
VMInstanceDao _vmInstanceDao; VMInstanceDao _vmInstanceDao;
@Mock @Mock
ServiceOfferingDao _offeringDao;
@Mock
VMTemplateDao _templateDao; VMTemplateDao _templateDao;
@Mock @Mock
VolumeDao _volsDao; VolumeDao _volsDao;
@ -150,6 +154,8 @@ public class VirtualMachineManagerImplTest {
@Mock @Mock
VMInstanceVO _vmInstance; VMInstanceVO _vmInstance;
@Mock @Mock
ServiceOfferingVO _serviceOfferingMock;
@Mock
HostVO _host; HostVO _host;
@Mock @Mock
VMTemplateVO _templateMock; VMTemplateVO _templateMock;
@ -228,6 +234,8 @@ public class VirtualMachineManagerImplTest {
_vmMgr._uservmDetailsDao = _vmDetailsDao; _vmMgr._uservmDetailsDao = _vmDetailsDao;
_vmMgr._entityMgr = _entityMgr; _vmMgr._entityMgr = _entityMgr;
_vmMgr._configDepot = _configDepot; _vmMgr._configDepot = _configDepot;
_vmMgr._offeringDao = _offeringDao;
_vmMgr.hostAllocators = new ArrayList<>();
when(_vmMock.getId()).thenReturn(314l); when(_vmMock.getId()).thenReturn(314l);
when(_vmInstance.getId()).thenReturn(1L); when(_vmInstance.getId()).thenReturn(1L);
@ -514,4 +522,24 @@ public class VirtualMachineManagerImplTest {
assertTrue(_vmMgr.getExecuteInSequence(HypervisorType.VMware) == HypervisorGuru.VmwareFullClone.value()); assertTrue(_vmMgr.getExecuteInSequence(HypervisorType.VMware) == HypervisorGuru.VmwareFullClone.value());
assertTrue(_vmMgr.getExecuteInSequence(HypervisorType.Ovm3) == VirtualMachineManager.ExecuteInSequence.value()); assertTrue(_vmMgr.getExecuteInSequence(HypervisorType.Ovm3) == VirtualMachineManager.ExecuteInSequence.value());
} }
@Test
public void testCheckIfCanUpgrade() throws Exception {
when(_vmInstance.getState()).thenReturn(State.Stopped);
when(_serviceOfferingMock.isDynamic()).thenReturn(true);
when(_vmInstance.getServiceOfferingId()).thenReturn(1l);
when(_serviceOfferingMock.getId()).thenReturn(2l);
ServiceOfferingVO mockCurrentServiceOffering = mock(ServiceOfferingVO.class);
when(_offeringDao.findByIdIncludingRemoved(anyLong(), anyLong())).thenReturn(mockCurrentServiceOffering);
when(mockCurrentServiceOffering.getUseLocalStorage()).thenReturn(true);
when(_serviceOfferingMock.getUseLocalStorage()).thenReturn(true);
when(mockCurrentServiceOffering.getSystemUse()).thenReturn(true);
when(_serviceOfferingMock.getSystemUse()).thenReturn(true);
when(mockCurrentServiceOffering.getTags()).thenReturn("x,y");
when(_serviceOfferingMock.getTags()).thenReturn("z,x,y");
_vmMgr.checkIfCanUpgrade(_vmInstance, _serviceOfferingMock);
}
} }

View File

@ -237,7 +237,7 @@ import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
import com.cloud.hypervisor.vmware.mo.NetworkDetails; import com.cloud.hypervisor.vmware.mo.NetworkDetails;
import com.cloud.hypervisor.vmware.mo.TaskMO; import com.cloud.hypervisor.vmware.mo.TaskMO;
import com.cloud.hypervisor.vmware.mo.VirtualEthernetCardType; import com.cloud.hypervisor.vmware.mo.VirtualEthernetCardType;
import com.cloud.hypervisor.vmware.mo.VirtualMachineDiskInfo; import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
import com.cloud.hypervisor.vmware.mo.VirtualMachineDiskInfoBuilder; import com.cloud.hypervisor.vmware.mo.VirtualMachineDiskInfoBuilder;
import com.cloud.hypervisor.vmware.mo.VirtualMachineMO; import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
import com.cloud.hypervisor.vmware.mo.VirtualSwitchType; import com.cloud.hypervisor.vmware.mo.VirtualSwitchType;
@ -1452,7 +1452,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
s_logger.error(msg); s_logger.error(msg);
throw new Exception(msg); throw new Exception(msg);
} }
String guestOsId = translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs(), vmSpec.getPlatformEmulator()).value();
DiskTO[] disks = validateDisks(vmSpec.getDisks()); DiskTO[] disks = validateDisks(vmSpec.getDisks());
assert (disks.length > 0); assert (disks.length > 0);
NicTO[] nics = vmSpec.getNics(); NicTO[] nics = vmSpec.getNics();
@ -1565,7 +1565,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
tearDownVm(vmMo); tearDownVm(vmMo);
}else if (!hyperHost.createBlankVm(vmNameOnVcenter, vmInternalCSName, vmSpec.getCpus(), vmSpec.getMaxSpeed().intValue(), }else if (!hyperHost.createBlankVm(vmNameOnVcenter, vmInternalCSName, vmSpec.getCpus(), vmSpec.getMaxSpeed().intValue(),
getReservedCpuMHZ(vmSpec), vmSpec.getLimitCpuUse(), (int)(vmSpec.getMaxRam() / (1024 * 1024)), getReservedMemoryMb(vmSpec), getReservedCpuMHZ(vmSpec), vmSpec.getLimitCpuUse(), (int)(vmSpec.getMaxRam() / (1024 * 1024)), getReservedMemoryMb(vmSpec),
translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs(), vmSpec.getPlatformEmulator()).value(), rootDiskDataStoreDetails.first(), false, controllerInfo, systemVm)) { guestOsId, rootDiskDataStoreDetails.first(), false, controllerInfo, systemVm)) {
throw new Exception("Failed to create VM. vmName: " + vmInternalCSName); throw new Exception("Failed to create VM. vmName: " + vmInternalCSName);
} }
} }
@ -1589,7 +1589,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
} }
VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec(); VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec();
String guestOsId = translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs(), vmSpec.getPlatformEmulator()).value();
VmwareHelper.setBasicVmConfig(vmConfigSpec, vmSpec.getCpus(), vmSpec.getMaxSpeed(), VmwareHelper.setBasicVmConfig(vmConfigSpec, vmSpec.getCpus(), vmSpec.getMaxSpeed(),
getReservedCpuMHZ(vmSpec), (int)(vmSpec.getMaxRam() / (1024 * 1024)), getReservedMemoryMb(vmSpec), getReservedCpuMHZ(vmSpec), (int)(vmSpec.getMaxRam() / (1024 * 1024)), getReservedMemoryMb(vmSpec),

View File

@ -33,6 +33,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.google.common.base.Strings;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
@ -88,7 +89,7 @@ import com.cloud.hypervisor.vmware.mo.HostMO;
import com.cloud.hypervisor.vmware.mo.HostStorageSystemMO; import com.cloud.hypervisor.vmware.mo.HostStorageSystemMO;
import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper; import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
import com.cloud.hypervisor.vmware.mo.NetworkDetails; import com.cloud.hypervisor.vmware.mo.NetworkDetails;
import com.cloud.hypervisor.vmware.mo.VirtualMachineDiskInfo; import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
import com.cloud.hypervisor.vmware.mo.VirtualMachineMO; import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost; import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
import com.cloud.hypervisor.vmware.resource.VmwareResource; import com.cloud.hypervisor.vmware.resource.VmwareResource;
@ -1366,24 +1367,15 @@ public class VmwareStorageProcessor implements StorageProcessor {
AttachAnswer answer = new AttachAnswer(disk); AttachAnswer answer = new AttachAnswer(disk);
if (isAttach) { if (isAttach) {
String dataDiskController = controllerInfo.get(VmDetailConstants.DATA_DISK_CONTROLLER); String diskController = getLegacyVmDataDiskController();
String rootDiskController = controllerInfo.get(VmDetailConstants.ROOT_DISK_CONTROLLER); if (controllerInfo != null &&
DiskControllerType rootDiskControllerType = DiskControllerType.getType(rootDiskController); !Strings.isNullOrEmpty(controllerInfo.get(VmDetailConstants.DATA_DISK_CONTROLLER))) {
diskController = controllerInfo.get(VmDetailConstants.DATA_DISK_CONTROLLER);
if (dataDiskController == null) {
dataDiskController = getLegacyVmDataDiskController();
} else if ((rootDiskControllerType == DiskControllerType.lsilogic) ||
(rootDiskControllerType == DiskControllerType.lsisas1068) ||
(rootDiskControllerType == DiskControllerType.pvscsi) ||
(rootDiskControllerType == DiskControllerType.buslogic)) {
//TODO: Support mix of SCSI controller types for single VM. If root disk is already over
//a SCSI controller then use the same for data volume as well. This limitation will go once mix
//of SCSI controller types for single VM.
dataDiskController = rootDiskController;
} else if (DiskControllerType.getType(dataDiskController) == DiskControllerType.osdefault) {
dataDiskController = vmMo.getRecommendedDiskController(null);
} }
vmMo.attachDisk(new String[] {datastoreVolumePath}, morDs, dataDiskController); if (DiskControllerType.getType(diskController) == DiskControllerType.osdefault) {
diskController = vmMo.getRecommendedDiskController(null);
}
vmMo.attachDisk(new String[] {datastoreVolumePath}, morDs, diskController);
} else { } else {
vmMo.removeAllSnapshots(); vmMo.removeAllSnapshots();
vmMo.detachDisk(datastoreVolumePath, false); vmMo.detachDisk(datastoreVolumePath, false);

View File

@ -2620,11 +2620,11 @@ public class QueryManagerImpl extends ManagerBase implements QueryService, Confi
if(currentVmOffering == null) return offerings; if(currentVmOffering == null) return offerings;
List<String> currentTagsList = StringUtils.csvTagsToList(currentVmOffering.getTags()); List<String> currentTagsList = StringUtils.csvTagsToList(currentVmOffering.getTags());
// New offerings should be a subset of existing storage tags. Discard offerings who are not. // New service offering should have all the tags of the current service offering.
List<ServiceOfferingJoinVO> filteredOfferings = new ArrayList<>(); List<ServiceOfferingJoinVO> filteredOfferings = new ArrayList<>();
for (ServiceOfferingJoinVO offering : offerings){ for (ServiceOfferingJoinVO offering : offerings){
List<String> tags = StringUtils.csvTagsToList(offering.getTags()); List<String> newTagsList = StringUtils.csvTagsToList(offering.getTags());
if(currentTagsList.containsAll(tags)){ if(newTagsList.containsAll(currentTagsList)){
filteredOfferings.add(offering); filteredOfferings.add(offering);
} }
} }

View File

@ -30,8 +30,10 @@ import javax.inject.Inject;
import com.cloud.utils.EncryptionUtil; import com.cloud.utils.EncryptionUtil;
import com.cloud.utils.db.TransactionCallbackWithException; import com.cloud.utils.db.TransactionCallbackWithException;
import com.google.common.base.Strings;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
import org.apache.cloudstack.api.command.user.volume.GetUploadParamsForVolumeCmd; import org.apache.cloudstack.api.command.user.volume.GetUploadParamsForVolumeCmd;
import org.apache.cloudstack.api.response.GetUploadParamsResponse; import org.apache.cloudstack.api.response.GetUploadParamsResponse;
@ -39,6 +41,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand; import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand;
import org.apache.cloudstack.utils.imagestore.ImageStoreUtil; import org.apache.cloudstack.utils.imagestore.ImageStoreUtil;
import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
@ -112,12 +115,14 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.hypervisor.HypervisorCapabilitiesVO; import com.cloud.hypervisor.HypervisorCapabilitiesVO;
import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
import com.cloud.org.Grouping; import com.cloud.org.Grouping;
import com.cloud.serializer.GsonHelper;
import com.cloud.service.dao.ServiceOfferingDetailsDao; import com.cloud.service.dao.ServiceOfferingDetailsDao;
import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.dao.VolumeDetailsDao;
import com.cloud.storage.snapshot.SnapshotApiService; import com.cloud.storage.snapshot.SnapshotApiService;
import com.cloud.storage.snapshot.SnapshotManager; import com.cloud.storage.snapshot.SnapshotManager;
import com.cloud.template.TemplateManager; import com.cloud.template.TemplateManager;
@ -146,6 +151,7 @@ import com.cloud.utils.db.UUIDManager;
import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.fsm.NoTransitionException; import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.utils.fsm.StateMachine2; import com.cloud.utils.fsm.StateMachine2;
import com.cloud.vm.UserVmManager;
import com.cloud.vm.UserVmVO; import com.cloud.vm.UserVmVO;
import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine;
@ -191,6 +197,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
@Inject @Inject
VolumeDao _volsDao; VolumeDao _volsDao;
@Inject @Inject
VolumeDetailsDao _volDetailDao;
@Inject
HostDao _hostDao; HostDao _hostDao;
@Inject @Inject
SnapshotDao _snapshotDao; SnapshotDao _snapshotDao;
@ -240,6 +248,9 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
VmWorkJobDao _workJobDao; VmWorkJobDao _workJobDao;
@Inject @Inject
ClusterDetailsDao _clusterDetailsDao; ClusterDetailsDao _clusterDetailsDao;
@Inject
UserVmManager _userVmMgr;
protected Gson _gson;
private List<StoragePoolAllocator> _storagePoolAllocators; private List<StoragePoolAllocator> _storagePoolAllocators;
@ -253,6 +264,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
protected VolumeApiServiceImpl() { protected VolumeApiServiceImpl() {
_volStateMachine = Volume.State.getStateMachine(); _volStateMachine = Volume.State.getStateMachine();
_gson = GsonHelper.getGsonLogger();
} }
/* /*
@ -1835,6 +1847,26 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
} }
} }
public void updateMissingRootDiskController(final VMInstanceVO vm, final String rootVolChainInfo) {
if (vm == null || !VirtualMachine.Type.User.equals(vm.getType()) || Strings.isNullOrEmpty(rootVolChainInfo)) {
return;
}
String rootDiskController = null;
try {
final VirtualMachineDiskInfo infoInChain = _gson.fromJson(rootVolChainInfo, VirtualMachineDiskInfo.class);
if (infoInChain != null) {
rootDiskController = infoInChain.getControllerFromDeviceBusName();
}
final UserVmVO userVmVo = _userVmDao.findById(vm.getId());
if ((rootDiskController != null) && (!rootDiskController.isEmpty())) {
_userVmDao.loadDetails(userVmVo);
_userVmMgr.persistDeviceBusInfo(userVmVo, rootDiskController);
}
} catch (JsonParseException e) {
s_logger.debug("Error parsing chain info json: " + e.getMessage());
}
}
@DB @DB
@Override @Override
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_MIGRATE, eventDescription = "migrating volume", async = true) @ActionEvent(eventType = EventTypes.EVENT_VOLUME_MIGRATE, eventDescription = "migrating volume", async = true)
@ -1924,6 +1956,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
throw new InvalidParameterValueException("Cannot migrate ROOT volume of a stopped VM to a storage pool in a different VMware datacenter"); throw new InvalidParameterValueException("Cannot migrate ROOT volume of a stopped VM to a storage pool in a different VMware datacenter");
} }
} }
updateMissingRootDiskController(vm, vol.getChainInfo());
} }
} }
} }
@ -2475,6 +2508,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
controllerInfo.put(VmDetailConstants.ROOT_DISK_CONTROLLER, vm.getDetail(VmDetailConstants.ROOT_DISK_CONTROLLER)); controllerInfo.put(VmDetailConstants.ROOT_DISK_CONTROLLER, vm.getDetail(VmDetailConstants.ROOT_DISK_CONTROLLER));
controllerInfo.put(VmDetailConstants.DATA_DISK_CONTROLLER, vm.getDetail(VmDetailConstants.DATA_DISK_CONTROLLER)); controllerInfo.put(VmDetailConstants.DATA_DISK_CONTROLLER, vm.getDetail(VmDetailConstants.DATA_DISK_CONTROLLER));
cmd.setControllerInfo(controllerInfo); cmd.setControllerInfo(controllerInfo);
s_logger.debug("Attach volume id:" + volumeToAttach.getId() + " on VM id:" + vm.getId() + " has controller info:" + controllerInfo);
try { try {
answer = (AttachAnswer)_agentMgr.send(hostId, cmd); answer = (AttachAnswer)_agentMgr.send(hostId, cmd);

View File

@ -114,4 +114,6 @@ public interface UserVmManager extends UserVmService {
public void removeCustomOfferingDetails(long vmId); public void removeCustomOfferingDetails(long vmId);
void generateUsageEvent(VirtualMachine vm, boolean isDisplay, String eventType); void generateUsageEvent(VirtualMachine vm, boolean isDisplay, String eventType);
void persistDeviceBusInfo(UserVmVO paramUserVmVO, String paramString);
} }

View File

@ -89,6 +89,7 @@ import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import com.cloud.agent.AgentManager; import com.cloud.agent.AgentManager;
@ -5452,6 +5453,17 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
} }
public void persistDeviceBusInfo(UserVmVO vm, String rootDiskController) {
String existingVmRootDiskController = vm.getDetail(VmDetailConstants.ROOT_DISK_CONTROLLER);
if (StringUtils.isEmpty(existingVmRootDiskController) && !StringUtils.isEmpty(rootDiskController)) {
vm.setDetail(VmDetailConstants.ROOT_DISK_CONTROLLER, rootDiskController);
_vmDao.saveDetails(vm);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Persisted device bus information rootDiskController=" + rootDiskController + " for vm: " + vm.getDisplayName());
}
}
}
@Override @Override
public String getConfigComponentName() { public String getConfigComponentName() {
return UserVmManager.class.getSimpleName(); return UserVmManager.class.getSimpleName();

View File

@ -18,7 +18,11 @@ package com.cloud.storage;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import java.lang.reflect.Field; import java.lang.reflect.Field;
@ -28,7 +32,10 @@ import java.util.UUID;
import javax.inject.Inject; import javax.inject.Inject;
import com.cloud.serializer.GsonHelper;
import com.cloud.user.User; import com.cloud.user.User;
import com.cloud.vm.UserVmManager;
import com.cloud.vm.VirtualMachine;
import junit.framework.Assert; import junit.framework.Assert;
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
import org.junit.After; import org.junit.After;
@ -101,6 +108,8 @@ public class VolumeApiServiceImplTest {
VolumeService volService; VolumeService volService;
@Mock @Mock
CreateVolumeCmd createVol; CreateVolumeCmd createVol;
@Mock
UserVmManager _userVmMgr;
DetachVolumeCmd detachCmd = new DetachVolumeCmd(); DetachVolumeCmd detachCmd = new DetachVolumeCmd();
Class<?> _detachCmdClass = detachCmd.getClass(); Class<?> _detachCmdClass = detachCmd.getClass();
@ -118,6 +127,8 @@ public class VolumeApiServiceImplTest {
_svc._jobMgr = _jobMgr; _svc._jobMgr = _jobMgr;
_svc.volFactory = _volFactory; _svc.volFactory = _volFactory;
_svc.volService = volService; _svc.volService = volService;
_svc._userVmMgr = _userVmMgr;
_svc._gson = GsonHelper.getGsonLogger();
// mock caller context // mock caller context
AccountVO account = new AccountVO("admin", 1L, "networkDomain", Account.ACCOUNT_TYPE_NORMAL, "uuid"); AccountVO account = new AccountVO("admin", 1L, "networkDomain", Account.ACCOUNT_TYPE_NORMAL, "uuid");
@ -383,6 +394,20 @@ public class VolumeApiServiceImplTest {
Assert.assertSame(_svc.getVolumeNameFromCommand(createVol), "abc"); Assert.assertSame(_svc.getVolumeNameFromCommand(createVol), "abc");
} }
@Test
public void testUpdateMissingRootDiskControllerWithNullChainInfo() {
_svc.updateMissingRootDiskController(null, null);
verify(_svc._userVmMgr, times(0)).persistDeviceBusInfo(any(UserVmVO.class), anyString());
}
@Test
public void testUpdateMissingRootDiskControllerWithValidChainInfo() {
UserVmVO vm = _svc._userVmDao.findById(1L);
assert vm.getType() == VirtualMachine.Type.User;
_svc.updateMissingRootDiskController(vm, "{\"diskDeviceBusName\":\"scsi0:0\",\"diskChain\":[\"[somedatastore] i-3-VM-somePath/ROOT-1.vmdk\"]}");
verify(_svc._userVmMgr, times(1)).persistDeviceBusInfo(any(UserVmVO.class), eq("scsi"));
}
@After @After
public void tearDown() { public void tearDown() {
CallContext.unregister(); CallContext.unregister();

View File

@ -928,4 +928,25 @@ public class UserVmManagerTest {
CallContext.unregister(); CallContext.unregister();
} }
} }
@Test
public void testPersistDeviceBusInfoWithNullController() {
when(_vmMock.getDetail(any(String.class))).thenReturn(null);
_userVmMgr.persistDeviceBusInfo(_vmMock, null);
verify(_vmDao, times(0)).saveDetails(any(UserVmVO.class));
}
@Test
public void testPersistDeviceBusInfoWithEmptyController() {
when(_vmMock.getDetail(any(String.class))).thenReturn("");
_userVmMgr.persistDeviceBusInfo(_vmMock, "");
verify(_vmDao, times(0)).saveDetails(any(UserVmVO.class));
}
@Test
public void testPersistDeviceBusInfo() {
when(_vmMock.getDetail(any(String.class))).thenReturn(null);
_userVmMgr.persistDeviceBusInfo(_vmMock, "lsilogic");
verify(_vmDao, times(1)).saveDetails(any(UserVmVO.class));
}
} }

View File

@ -134,7 +134,7 @@ class TestLoadBalance(cloudstackTestCase):
self.services['lbrule']["publicport"], self.services['lbrule']["publicport"],
self.vm_1.username, self.vm_1.username,
self.vm_1.password, self.vm_1.password,
retries=5 retries=10
) )
unameCmd.append(ssh_1.execute("uname")[0]) unameCmd.append(ssh_1.execute("uname")[0])
self.debug(unameCmd) self.debug(unameCmd)

View File

@ -15,14 +15,13 @@
// specific language governing permissions and limitations // specific language governing permissions and limitations
// under the License. // under the License.
package com.cloud.hypervisor.vmware.mo; package org.apache.cloudstack.utils.volume;
import org.apache.commons.lang.StringUtils;
public class VirtualMachineDiskInfo { public class VirtualMachineDiskInfo {
String diskDeviceBusName; private String diskDeviceBusName;
String[] diskChain; private String[] diskChain;
public VirtualMachineDiskInfo() {
}
public String getDiskDeviceBusName() { public String getDiskDeviceBusName() {
return diskDeviceBusName; return diskDeviceBusName;
@ -39,4 +38,11 @@ public class VirtualMachineDiskInfo {
public void setDiskChain(String[] diskChain) { public void setDiskChain(String[] diskChain) {
this.diskChain = diskChain; this.diskChain = diskChain;
} }
public String getControllerFromDeviceBusName() {
if (StringUtils.isEmpty(diskDeviceBusName) || !diskDeviceBusName.contains(":")) {
return null;
}
return diskDeviceBusName.substring(0, diskDeviceBusName.indexOf(":") - 1);
}
} }

View File

@ -0,0 +1,55 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
package org.apache.cloudstack.utils.volume;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class VirtualMachineDiskInfoTest {
@Test
public void testGetControllerFromDeviceBusName() {
VirtualMachineDiskInfo vmDiskInfo = new VirtualMachineDiskInfo();
vmDiskInfo.setDiskDeviceBusName("scsi0:0");
String[] diskChain = new String[]{"[somedatastore] i-3-VM-somePath/ROOT-1.vmdk"};
vmDiskInfo.setDiskChain(diskChain);
Assert.assertEquals(vmDiskInfo.getControllerFromDeviceBusName(), "scsi");
Assert.assertArrayEquals(vmDiskInfo.getDiskChain(), diskChain);
}
@Test
public void testGetControllerFromDeviceBusNameWithInvalidBusName() {
VirtualMachineDiskInfo vmDiskInfo = new VirtualMachineDiskInfo();
vmDiskInfo.setDiskDeviceBusName("scsi0");
Assert.assertEquals(vmDiskInfo.getControllerFromDeviceBusName(), null);
}
@Test
public void testGSonDeserialization() throws JsonParseException {
VirtualMachineDiskInfo infoInChain = new GsonBuilder().create().fromJson("{\"diskDeviceBusName\":\"scsi0:0\",\"diskChain\":[\"[somedatastore] i-3-VM-somePath/ROOT-1.vmdk\"]}", VirtualMachineDiskInfo.class);
Assert.assertEquals(infoInChain.getDiskDeviceBusName(), "scsi0:0");
Assert.assertEquals(infoInChain.getControllerFromDeviceBusName(), "scsi");
}
}

View File

@ -17,6 +17,8 @@
package com.cloud.hypervisor.vmware.mo; package com.cloud.hypervisor.vmware.mo;
import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;

View File

@ -2137,7 +2137,7 @@ public class VirtualMachineMO extends BaseMO {
} }
assert (false); assert (false);
throw new Exception(diskController + " Controller Not Found"); throw new IllegalStateException("Scsi disk controller of type " + diskController + " not found among configured devices.");
} }
public int getScsiDiskControllerKeyNoException(String diskController) throws Exception { public int getScsiDiskControllerKeyNoException(String diskController) throws Exception {