You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by mu...@apache.org on 2014/03/11 15:26:59 UTC
[37/50] [abbrv] CLOUDSTACK-4760 : Enabling GPU support for XenServer.
CLOUDSTACK-4762 : Enabling VGPU support for XenServer.
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c7d31fe2/server/src/com/cloud/network/NetworkUsageManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/NetworkUsageManagerImpl.java b/server/src/com/cloud/network/NetworkUsageManagerImpl.java
index e9b0393..13eb210 100755
--- a/server/src/com/cloud/network/NetworkUsageManagerImpl.java
+++ b/server/src/com/cloud/network/NetworkUsageManagerImpl.java
@@ -57,6 +57,7 @@ import com.cloud.event.UsageEventVO;
import com.cloud.event.dao.UsageEventDao;
import com.cloud.exception.AgentUnavailableException;
import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.gpu.dao.HostGpuGroupsDao;
import com.cloud.host.DetailVO;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
@@ -116,6 +117,8 @@ public class NetworkUsageManagerImpl extends ManagerBase implements NetworkUsage
@Inject
HostDetailsDao _detailsDao;
@Inject
+ HostGpuGroupsDao _hostGpuGroupsDao;
+ @Inject
AccountManager _accountMgr;
@Inject
NetworkDao _networksDao = null;
@@ -537,6 +540,7 @@ public class NetworkUsageManagerImpl extends ManagerBase implements NetworkUsage
long hostId = host.getId();
_agentMgr.disconnectWithoutInvestigation(hostId, Status.Event.Remove);
_detailsDao.deleteDetails(hostId);
+ _hostGpuGroupsDao.deleteGpuEntries(hostId);
host.setGuid(null);
_hostDao.update(hostId, host);
_hostDao.remove(hostId);
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c7d31fe2/server/src/com/cloud/resource/ResourceManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java
index adad85c..2625885 100755
--- a/server/src/com/cloud/resource/ResourceManagerImpl.java
+++ b/server/src/com/cloud/resource/ResourceManagerImpl.java
@@ -30,11 +30,6 @@ import javax.ejb.Local;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
-import org.apache.log4j.Logger;
-import org.springframework.stereotype.Component;
-
-import com.google.gson.Gson;
-
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.command.admin.cluster.AddClusterCmd;
import org.apache.cloudstack.api.command.admin.cluster.DeleteClusterCmd;
@@ -51,10 +46,14 @@ import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.utils.identity.ManagementServerNode;
import org.apache.commons.lang.ObjectUtils;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
import com.cloud.agent.AgentManager;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
+import com.cloud.agent.api.GetGPUStatsAnswer;
+import com.cloud.agent.api.GetGPUStatsCommand;
import com.cloud.agent.api.GetHostStatsAnswer;
import com.cloud.agent.api.GetHostStatsCommand;
import com.cloud.agent.api.MaintainAnswer;
@@ -64,6 +63,7 @@ import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupRoutingCommand;
import com.cloud.agent.api.UnsupportedAnswer;
import com.cloud.agent.api.UpdateHostPasswordCommand;
+import com.cloud.agent.api.to.GPUDeviceTO;
import com.cloud.agent.transport.Request;
import com.cloud.api.ApiDBUtils;
import com.cloud.capacity.Capacity;
@@ -97,6 +97,11 @@ import com.cloud.exception.DiscoveryException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceInUseException;
+import com.cloud.gpu.GPU.vGPUType;
+import com.cloud.gpu.HostGpuGroupsVO;
+import com.cloud.gpu.VGPUTypesVO;
+import com.cloud.gpu.dao.HostGpuGroupsDao;
+import com.cloud.gpu.dao.VGPUTypesDao;
import com.cloud.ha.HighAvailabilityManager;
import com.cloud.ha.HighAvailabilityManager.WorkType;
import com.cloud.host.DetailVO;
@@ -137,11 +142,14 @@ import com.cloud.utils.UriUtils;
import com.cloud.utils.component.Manager;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.db.DB;
+import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericSearchBuilder;
import com.cloud.utils.db.GlobalLock;
+import com.cloud.utils.db.JoinBuilder;
import com.cloud.utils.db.QueryBuilder;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.db.SearchCriteria.Func;
import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.utils.db.Transaction;
@@ -158,6 +166,7 @@ import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.VirtualMachineManager;
import com.cloud.vm.dao.VMInstanceDao;
+import com.google.gson.Gson;
@Component
@Local({ResourceManager.class, ResourceService.class})
@@ -193,6 +202,10 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
@Inject
private GuestOSCategoryDao _guestOSCategoryDao;
@Inject
+ protected HostGpuGroupsDao _hostGpuGroupsDao;
+ @Inject
+ protected VGPUTypesDao _vgpuTypesDao;
+ @Inject
private PrimaryDataStoreDao _storagePoolDao;
@Inject
private DataCenterIpAddressDao _privateIPAddressDao;
@@ -244,6 +257,8 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
private GenericSearchBuilder<HostVO, String> _hypervisorsInDC;
+ private SearchBuilder<HostGpuGroupsVO> _gpuAvailability;
+
private void insertListener(Integer event, ResourceListener listener) {
List<ResourceListener> lst = _lifeCycleListeners.get(event);
if (lst == null) {
@@ -827,6 +842,9 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
// delete host details
_hostDetailsDao.deleteDetails(hostId);
+ // if host is GPU enabled, delete GPU entries
+ _hostGpuGroupsDao.deleteGpuEntries(hostId);
+
host.setGuid(null);
Long clusterId = host.getClusterId();
host.setClusterId(null);
@@ -1329,6 +1347,14 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
_hypervisorsInDC.and("type", _hypervisorsInDC.entity().getType(), SearchCriteria.Op.EQ);
_hypervisorsInDC.done();
+ _gpuAvailability = _hostGpuGroupsDao.createSearchBuilder();
+ _gpuAvailability.and("hostId", _gpuAvailability.entity().getHostId(), Op.EQ);
+ SearchBuilder<VGPUTypesVO> join1 = _vgpuTypesDao.createSearchBuilder();
+ join1.and("vgpuType", join1.entity().getVgpuType(), Op.EQ);
+ join1.and("remainingCapacity", join1.entity().getRemainingCapacity(), Op.GT);
+ _gpuAvailability.join("groupId", join1, _gpuAvailability.entity().getId(), join1.entity().getGpuGroupId(), JoinBuilder.JoinType.INNER);
+ _gpuAvailability.done();
+
return true;
}
@@ -1958,6 +1984,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
host.setSpeed(ssCmd.getSpeed());
host.setHypervisorType(hyType);
host.setHypervisorVersion(ssCmd.getHypervisorVersion());
+ host.setGpuGroups(ssCmd.getGpuGroupDetails());
return host;
}
@@ -2474,6 +2501,66 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
}
@Override
+ public List<HostGpuGroupsVO> listAvailableGPUDevice(long hostId, String vgpuType) {
+ if (vgpuType == null) {
+ vgpuType = vGPUType.passthrough.getType();
+ }
+ Filter searchFilter = new Filter(VGPUTypesVO.class, "remainingCapacity", false, null, null);
+ SearchCriteria<HostGpuGroupsVO> sc = _gpuAvailability.create();
+ sc.setParameters("hostId", hostId);
+ sc.setJoinParameters("groupId", "vgpuType", vgpuType);
+ sc.setJoinParameters("groupId", "remainingCapacity", 0);
+ return _hostGpuGroupsDao.customSearch(sc, searchFilter);
+ }
+
+ @Override
+ public boolean isGPUDeviceAvailable(long hostId, String vgpuType) {
+ if(!listAvailableGPUDevice(hostId, vgpuType).isEmpty()) {
+ return true;
+ } else {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Host ID: "+ hostId +" does not have GPU device available");
+ }
+ return false;
+ }
+ }
+
+ @Override
+ public GPUDeviceTO getGPUDevice(long hostId, String vgpuType) {
+ HostGpuGroupsVO gpuDevice = listAvailableGPUDevice(hostId, vgpuType).get(0);
+ return new GPUDeviceTO(gpuDevice.getGroupName(), vgpuType, null);
+ }
+
+ @Override
+ public void updateGPUDetails(long hostId, HashMap<String, HashMap<String, Long>> groupDetails) {
+ // Update GPU group capacity
+ TransactionLegacy txn = TransactionLegacy.currentTxn();
+ txn.start();
+ _hostGpuGroupsDao.persist(hostId, new ArrayList<String>(groupDetails.keySet()));
+ _vgpuTypesDao.persist(hostId, groupDetails);
+ txn.commit();
+ }
+
+ @Override
+ public HashMap<String, HashMap<String, Long>> getGPUStatistics(HostVO host) {
+ Answer answer = _agentMgr.easySend(host.getId(), new GetGPUStatsCommand(host.getGuid(), host.getName()));
+ if (answer != null && (answer instanceof UnsupportedAnswer)) {
+ return null;
+ }
+ if (answer == null || !answer.getResult()) {
+ String msg = "Unable to obtain GPU stats for host " + host.getName();
+ s_logger.warn(msg);
+ return null;
+ } else {
+ // now construct the result object
+ if (answer instanceof GetGPUStatsAnswer) {
+ return ((GetGPUStatsAnswer)answer).getGroupDetails();
+ }
+ }
+ return null;
+ }
+
+ @Override
@DB
@ActionEvent(eventType = EventTypes.EVENT_HOST_RESERVATION_RELEASE, eventDescription = "releasing host reservation", async = true)
public boolean releaseHostReservation(final Long hostId) {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c7d31fe2/server/src/com/cloud/server/ManagementServerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java
index 49a9eb5..663d4e5 100755
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -508,6 +508,7 @@ import com.cloud.exception.OperationTimedoutException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.VirtualMachineMigrationException;
+import com.cloud.gpu.GPU;
import com.cloud.ha.HighAvailabilityManager;
import com.cloud.host.DetailVO;
import com.cloud.host.Host;
@@ -539,6 +540,7 @@ import com.cloud.server.ResourceTag.ResourceObjectType;
import com.cloud.server.auth.UserAuthenticator;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao;
+import com.cloud.service.dao.ServiceOfferingDetailsDao;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.GuestOS;
import com.cloud.storage.GuestOSCategoryVO;
@@ -700,6 +702,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
private ResourceTagDao _resourceTagDao;
@Inject
private ImageStoreDao _imgStoreDao;
+ @Inject
+ private ServiceOfferingDetailsDao _serviceOfferingDetailsDao;
+
@Inject
private ProjectManager _projectMgr;
@@ -1059,6 +1064,13 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
throw ex;
}
+ if(_serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) {
+ s_logger.info(" Live Migration of GPU enabled VM : " + vm.getInstanceName()+ " is not supported");
+ // Return empty list.
+ return new Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>>(new Pair<List <? extends Host>,
+ Integer>(new ArrayList<HostVO>(), new Integer(0)), new ArrayList<Host>(), new HashMap<Host, Boolean>());
+ }
+
if (!vm.getHypervisorType().equals(HypervisorType.XenServer) && !vm.getHypervisorType().equals(HypervisorType.VMware) && !vm.getHypervisorType().equals(HypervisorType.KVM)
&& !vm.getHypervisorType().equals(HypervisorType.Ovm) && !vm.getHypervisorType().equals(HypervisorType.Hyperv)) {
if (s_logger.isDebugEnabled()) {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c7d31fe2/server/src/com/cloud/server/StatsCollector.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java
index 548587c..067ed00 100755
--- a/server/src/com/cloud/server/StatsCollector.java
+++ b/server/src/com/cloud/server/StatsCollector.java
@@ -54,6 +54,7 @@ import com.cloud.agent.api.VmStatsEntry;
import com.cloud.cluster.ManagementServerHostVO;
import com.cloud.cluster.dao.ManagementServerHostDao;
import com.cloud.exception.StorageUnavailableException;
+import com.cloud.gpu.dao.HostGpuGroupsDao;
import com.cloud.host.Host;
import com.cloud.host.HostStats;
import com.cloud.host.HostVO;
@@ -175,6 +176,8 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
private AutoScaleVmProfileDao _asProfileDao;
@Inject
private ServiceOfferingDao _serviceOfferingDao;
+ @Inject
+ private HostGpuGroupsDao _hostGpuGroupsDao;
private ConcurrentHashMap<Long, HostStats> _hostStats = new ConcurrentHashMap<Long, HostStats>();
private final ConcurrentHashMap<Long, VmStats> _VmStats = new ConcurrentHashMap<Long, VmStats>();
@@ -188,6 +191,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
long volumeStatsInterval = -1L;
long autoScaleStatsInterval = -1L;
int vmDiskStatsInterval = 0;
+ List<Long> hostIds = null;
private ScheduledExecutorService _diskStatsUpdateExecutor;
private int _usageAggregationRange = 1440;
@@ -325,6 +329,23 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
}
}
_hostStats = hostStats;
+ // Get a subset of hosts with GPU support from the list of "hosts"
+ List<HostVO> gpuEnabledHosts = new ArrayList<HostVO>();
+ if (hostIds != null) {
+ for (HostVO host : hosts) {
+ if (hostIds.contains(host.getId())) {
+ gpuEnabledHosts.add(host);
+ }
+ }
+ } else {
+ // Check for all the hosts managed by CloudStack.
+ gpuEnabledHosts = hosts;
+ }
+ for (HostVO host : gpuEnabledHosts) {
+ HashMap<String, HashMap<String, Long>> groupDetails = _resourceMgr.getGPUStatistics(host);
+ _resourceMgr.updateGPUDetails(host.getId(), groupDetails);
+ }
+ hostIds = _hostGpuGroupsDao.listHostIds();
} catch (Throwable t) {
s_logger.error("Error trying to retrieve host stats", t);
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c7d31fe2/server/src/com/cloud/storage/VolumeApiServiceImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/com/cloud/storage/VolumeApiServiceImpl.java
index 17461c0..acc922f 100644
--- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java
+++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java
@@ -92,12 +92,14 @@ import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.StorageUnavailableException;
+import com.cloud.gpu.GPU;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.hypervisor.HypervisorCapabilitiesVO;
import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
import com.cloud.org.Grouping;
+import com.cloud.service.dao.ServiceOfferingDetailsDao;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.SnapshotDao;
@@ -171,6 +173,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
@Inject
private SnapshotDao _snapshotDao;
@Inject
+ protected ServiceOfferingDetailsDao _serviceOfferingDetailsDao;
+ @Inject
StoragePoolDetailsDao storagePoolDetailsDao;
@Inject
private UserVmDao _userVmDao;
@@ -1466,6 +1470,10 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
}
if (vm != null && vm.getState() == State.Running) {
+ // Check if the VM is GPU enabled.
+ if(_serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) {
+ throw new InvalidParameterValueException("Live Migration of GPU enabled VM is not supported");
+ }
// Check if the underlying hypervisor supports storage motion.
Long hostId = vm.getHostId();
if (hostId != null) {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c7d31fe2/server/src/com/cloud/vm/UserVmManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java
index d1df3c1..be00aa8 100755
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -137,6 +137,7 @@ import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.StorageUnavailableException;
import com.cloud.exception.VirtualMachineMigrationException;
+import com.cloud.gpu.GPU;
import com.cloud.ha.HighAvailabilityManager;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
@@ -3853,6 +3854,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
ex.addProxyObject(vm.getUuid(), "vmId");
throw ex;
}
+
+ if(serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) {
+ throw new InvalidParameterValueException("Live Migration of GPU enabled VM is not supported");
+ }
+
if (!vm.getHypervisorType().equals(HypervisorType.XenServer) && !vm.getHypervisorType().equals(HypervisorType.VMware) && !vm.getHypervisorType().equals(HypervisorType.KVM)
&& !vm.getHypervisorType().equals(HypervisorType.Ovm) && !vm.getHypervisorType().equals(HypervisorType.Hyperv)
&& !vm.getHypervisorType().equals(HypervisorType.Simulator)) {
@@ -4164,6 +4170,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
throw ex;
}
+ if(serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) {
+ throw new InvalidParameterValueException("Live Migration of GPU enabled VM is not supported");
+ }
+
if (!vm.getHypervisorType().equals(HypervisorType.XenServer) && !vm.getHypervisorType().equals(HypervisorType.VMware) && !vm.getHypervisorType().equals(HypervisorType.KVM)
&& !vm.getHypervisorType().equals(HypervisorType.Ovm) && !vm.getHypervisorType().equals(HypervisorType.Simulator)) {
throw new InvalidParameterValueException("Unsupported hypervisor type for vm migration, we support" + " XenServer/VMware/KVM only");
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c7d31fe2/server/test/com/cloud/resource/MockResourceManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/resource/MockResourceManagerImpl.java b/server/test/com/cloud/resource/MockResourceManagerImpl.java
index 5599e8c..e6bf9a2 100644
--- a/server/test/com/cloud/resource/MockResourceManagerImpl.java
+++ b/server/test/com/cloud/resource/MockResourceManagerImpl.java
@@ -17,6 +17,7 @@
package com.cloud.resource;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -35,6 +36,7 @@ import org.apache.cloudstack.api.command.admin.host.UpdateHostPasswordCmd;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupRoutingCommand;
+import com.cloud.agent.api.to.GPUDeviceTO;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.dc.PodCluster;
@@ -42,6 +44,7 @@ import com.cloud.exception.AgentUnavailableException;
import com.cloud.exception.DiscoveryException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceInUseException;
+import com.cloud.gpu.HostGpuGroupsVO;
import com.cloud.host.Host;
import com.cloud.host.Host.Type;
import com.cloud.host.HostStats;
@@ -554,4 +557,32 @@ public class MockResourceManagerImpl extends ManagerBase implements ResourceMana
return false;
}
+ @Override
+ public boolean isGPUDeviceAvailable(long hostId, String vgpuType) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public GPUDeviceTO getGPUDevice(long hostId, String vgpuType) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public List<HostGpuGroupsVO> listAvailableGPUDevice(long hostId, String vgpuType) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void updateGPUDetails(long hostId, HashMap<String, HashMap<String, Long>> deviceDetails) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public HashMap<String, HashMap<String, Long>> getGPUStatistics(HostVO host) {
+ // TODO Auto-generated method stub
+ return null;
+ }
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c7d31fe2/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java b/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java
index 751a3bd..fb63766 100644
--- a/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java
+++ b/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java
@@ -78,7 +78,9 @@ import com.cloud.exception.AffinityConflictException;
import com.cloud.exception.InsufficientServerCapacityException;
import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.resource.ResourceManager;
import com.cloud.service.ServiceOfferingVO;
+import com.cloud.service.dao.ServiceOfferingDetailsDao;
import com.cloud.storage.StorageManager;
import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.GuestOSCategoryDao;
@@ -239,6 +241,16 @@ public class DeploymentPlanningManagerImplTest {
}
@Bean
+ public ResourceManager resourceManager() {
+ return Mockito.mock(ResourceManager.class);
+ }
+
+ @Bean
+ public ServiceOfferingDetailsDao serviceOfferingDetailsDao() {
+ return Mockito.mock(ServiceOfferingDetailsDao.class);
+ }
+
+ @Bean
public DataStoreManager cataStoreManager() {
return Mockito.mock(DataStoreManager.class);
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c7d31fe2/server/test/resources/createNetworkOffering.xml
----------------------------------------------------------------------
diff --git a/server/test/resources/createNetworkOffering.xml b/server/test/resources/createNetworkOffering.xml
index c6228da..6ae1978 100644
--- a/server/test/resources/createNetworkOffering.xml
+++ b/server/test/resources/createNetworkOffering.xml
@@ -43,7 +43,9 @@
</bean>
<bean class="org.apache.cloudstack.networkoffering.ChildTestConfiguration" />
- <bean id="UservmDetailsDaoImpl" class="com.cloud.vm.dao.UserVmDetailsDaoImpl" />
+ <bean id="UservmDetailsDaoImpl" class="com.cloud.vm.dao.UserVmDetailsDaoImpl" />
+ <bean id="hostGpuGroupsDaoImpl" class="com.cloud.gpu.dao.HostGpuGroupsDaoImpl" />
+ <bean id="vGPUTypesDaoImpl" class="com.cloud.gpu.dao.VGPUTypesDaoImpl" />
<bean id="usageEventDaoImpl" class="com.cloud.event.dao.UsageEventDaoImpl" />
<bean id="usageEventDetailsDaoImpl" class="com.cloud.event.dao.UsageEventDetailsDaoImpl" />
</beans>
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c7d31fe2/setup/db/db/schema-430to440.sql
----------------------------------------------------------------------
diff --git a/setup/db/db/schema-430to440.sql b/setup/db/db/schema-430to440.sql
index be49b83..ee4cf21 100644
--- a/setup/db/db/schema-430to440.sql
+++ b/setup/db/db/schema-430to440.sql
@@ -592,4 +592,22 @@ CREATE VIEW `cloud`.`event_view` AS
`cloud`.`event` eve ON event.start_id = eve.id;
+DROP TABLE IF EXISTS `cloud`.`host_gpu_groups`;
+CREATE TABLE `cloud`.`host_gpu_groups` (
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+ `group_name` varchar(255) NOT NULL,
+ `host_id` bigint(20) unsigned NOT NULL,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `fk_host_gpu_groups__host_id` FOREIGN KEY (`host_id`) REFERENCES `host` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB CHARSET=utf8;
+
+DROP TABLE IF EXISTS `cloud`.`vgpu_types`;
+CREATE TABLE `cloud`.`vgpu_types` (
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+ `gpu_group_id` bigint(20) unsigned NOT NULL,
+ `vgpu_type` varchar(40) NOT NULL COMMENT 'vgpu type supported by this gpu group',
+ `remaining_vm_capacity` bigint(20) unsigned DEFAULT NULL COMMENT 'remaining vgpu can be created with this vgpu_type on the given gpu group',
+ PRIMARY KEY (`id`),
+ CONSTRAINT `fk_vgpu_types__gpu_group_id` FOREIGN KEY (`gpu_group_id`) REFERENCES `host_gpu_groups` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB CHARSET=utf8;
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c7d31fe2/test/integration/smoke/test_deploy_vgpu_enabled_vm.py
----------------------------------------------------------------------
diff --git a/test/integration/smoke/test_deploy_vgpu_enabled_vm.py b/test/integration/smoke/test_deploy_vgpu_enabled_vm.py
new file mode 100644
index 0000000..a09e87e
--- /dev/null
+++ b/test/integration/smoke/test_deploy_vgpu_enabled_vm.py
@@ -0,0 +1,227 @@
+# 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.
+
+#Test from the Marvin - Testing in Python wiki
+
+#All tests inherit from cloudstackTestCase
+from marvin.cloudstackTestCase import cloudstackTestCase
+
+#Import Integration Libraries
+
+#base - contains all resources as entities and defines create, delete, list operations on them
+from marvin.integration.lib.base import Account, VirtualMachine, ServiceOffering
+
+#utils - utility classes for common cleanup, external library wrappers etc
+from marvin.integration.lib.utils import cleanup_resources
+
+#common - commonly used methods for all tests are listed here
+from marvin.integration.lib.common import get_zone, get_domain, get_template
+
+from nose.plugins.attrib import attr
+
+class Services:
+ """Test VM Life Cycle Services
+ """
+
+ def __init__(self):
+ self.services = {
+ "disk_offering":{
+ "displaytext": "Small",
+ "name": "Small",
+ "disksize": 1
+ },
+ "account": {
+ "email": "test@test.com",
+ "firstname": "Test",
+ "lastname": "User",
+ "username": "test",
+ # Random characters are appended in create account to
+ # ensure unique username generated each time
+ "password": "password",
+ },
+ "vgpu260q": # Create a virtual machine instance with vgpu type as 260q
+ {
+ "displayname": "testserver",
+ "username": "root", # VM creds for SSH
+ "password": "password",
+ "ssh_port": 22,
+ "hypervisor": 'XenServer',
+ "privateport": 22,
+ "publicport": 22,
+ "protocol": 'TCP',
+ },
+ "vgpu140q": # Create a virtual machine instance with vgpu type as 140q
+ {
+ "displayname": "testserver",
+ "username": "root",
+ "password": "password",
+ "ssh_port": 22,
+ "hypervisor": 'XenServer',
+ "privateport": 22,
+ "publicport": 22,
+ "protocol": 'TCP',
+ },
+ "service_offerings":
+ {
+ "vgpu260qwin":
+ {
+ "name": "Windows Instance with vGPU260Q",
+ "displaytext": "Windows Instance with vGPU260Q",
+ "cpunumber": 2,
+ "cpuspeed": 1600, # in MHz
+ "memory": 3072, # In MBs
+ },
+ "vgpu140qwin":
+ {
+ # Small service offering ID to for change VM
+ # service offering from medium to small
+ "name": "Windows Instance with vGPU140Q",
+ "displaytext": "Windows Instance with vGPU140Q",
+ "cpunumber": 2,
+ "cpuspeed": 1600,
+ "memory": 3072,
+ }
+ },
+ "diskdevice": ['/dev/vdc', '/dev/vdb', '/dev/hdb', '/dev/hdc', '/dev/xvdd', '/dev/cdrom', '/dev/sr0', '/dev/cdrom1' ],
+ # Disk device where ISO is attached to instance
+ "mount_dir": "/mnt/tmp",
+ "sleep": 60,
+ "timeout": 10,
+ #Migrate VM to hostid
+ "ostype": 'Windows 7 (32-bit)',
+ # CentOS 5.3 (64-bit)
+ }
+
+
+class TestDeployvGPUenabledVM(cloudstackTestCase):
+ """Test deploy a vGPU enabled VM into a user account
+ """
+
+ def setUp(self):
+ self.services = Services().services
+ self.apiclient = self.testClient.getApiClient()
+
+ # Get Zone, Domain and Default Built-in template
+ self.domain = get_domain(self.apiclient, self.services)
+ self.zone = get_zone(self.apiclient, self.services)
+ self.services["mode"] = self.zone.networktype
+ # Before running this test, register a windows template with ostype as 'Windows 7 (32-bit)'
+ self.template = get_template(self.apiclient, self.zone.id, self.services["ostype"], templatetype='USER')
+
+ #create a user account
+ self.account = Account.create(
+ self.apiclient,
+ self.services["account"],
+ domainid=self.domain.id
+ )
+
+ self.services["vgpu260q"]["zoneid"] = self.zone.id
+ self.services["vgpu260q"]["template"] = self.template.id
+
+ self.services["vgpu140q"]["zoneid"] = self.zone.id
+ self.services["vgpu140q"]["template"] = self.template.id
+ #create a service offering
+ self.service_offering = ServiceOffering.create(
+ self.apiclient,
+ self.services["service_offerings"]["vgpu260qwin"],
+ serviceofferingdetails={'pciDevice': 'VGPU'}
+ )
+ #build cleanup list
+ self.cleanup = [
+ self.service_offering,
+ self.account
+ ]
+
+ @attr(tags = ['advanced', 'simulator', 'basic', 'vgpu'])
+ def test_deploy_vgpu_enabled_vm(self):
+ """Test Deploy Virtual Machine
+
+ # Validate the following:
+ # 1. Virtual Machine is accessible via SSH
+ # 2. Virtual Machine is vGPU enabled (via SSH)
+ # 3. listVirtualMachines returns accurate information
+ """
+ self.virtual_machine = VirtualMachine.create(
+ self.apiclient,
+ self.services["vgpu260q"],
+ accountid=self.account.name,
+ domainid=self.account.domainid,
+ serviceofferingid=self.service_offering.id,
+ mode=self.services['mode']
+ )
+
+ list_vms = VirtualMachine.list(self.apiclient, id=self.virtual_machine.id)
+
+ self.debug(
+ "Verify listVirtualMachines response for virtual machine: %s"\
+ % self.virtual_machine.id
+ )
+
+ self.assertEqual(
+ isinstance(list_vms, list),
+ True,
+ "List VM response was not a valid list"
+ )
+ self.assertNotEqual(
+ len(list_vms),
+ 0,
+ "List VM response was empty"
+ )
+
+ vm = list_vms[0]
+ self.assertEqual(
+ vm.id,
+ self.virtual_machine.id,
+ "Virtual Machine ids do not match"
+ )
+ self.assertEqual(
+ vm.name,
+ self.virtual_machine.name,
+ "Virtual Machine names do not match"
+ )
+ self.assertEqual(
+ vm.state,
+ "Running",
+ msg="VM is not in Running state"
+ )
+ list_hosts = list_hosts(
+ self.apiclient,
+ id=vm.hostid
+ )
+ hostip = list_hosts[0].ipaddress
+ try:
+ sshClient = SshClient(host=hostip, port=22, user='root',passwd=self.services["host_password"])
+ res = sshClient.execute("xe vgpu-list vm-name-label=%s params=type-uuid %s" % (
+ vm.instancename
+ ))
+ self.debug("SSH result: %s" % res)
+ except Exception as e:
+ self.fail("SSH Access failed for %s: %s" % \
+ (hostip, e)
+ )
+ result = str(res)
+ self.assertEqual(
+ result.count("type-uuid"),
+ 1,
+ "VM is vGPU enabled."
+ )
+
+ def tearDown(self):
+ try:
+ cleanup_resources(self.apiclient, self.cleanup)
+ except Exception as e:
+ self.debug("Warning! Exception in tearDown: %s" % e)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c7d31fe2/tools/marvin/marvin/integration/lib/base.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py
index 7449d8c..27a26b8 100755
--- a/tools/marvin/marvin/integration/lib/base.py
+++ b/tools/marvin/marvin/integration/lib/base.py
@@ -1462,6 +1462,9 @@ class ServiceOffering:
if "deploymentplanner" in services:
cmd.deploymentplanner = services["deploymentplanner"]
+ if "serviceofferingdetails" in services:
+ cmd.serviceofferingdetails.append({services['serviceofferingdetails']})
+
if "isvolatile" in services:
cmd.isvolatile = services["isvolatile"]
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c7d31fe2/ui/scripts/configuration.js
----------------------------------------------------------------------
diff --git a/ui/scripts/configuration.js b/ui/scripts/configuration.js
index e3c35af..8666042 100644
--- a/ui/scripts/configuration.js
+++ b/ui/scripts/configuration.js
@@ -361,6 +361,71 @@
}
},
+ pciDevice: {
+ label: 'GPU Type',
+ select: function(args) {
+ var items = [];
+ items.push({
+ id: '',
+ description: ''
+ });
+ items.push({
+ id: 'GPU_Passthrough',
+ description: 'GPU-Passthrough'
+ });
+ items.push({
+ id: 'VGPU',
+ description: 'VGPU'
+ });
+ args.response.success({
+ data: items
+ });
+ args.$select.change(function() {
+ var $form = $(this).closest('form');
+ var $fields = $form.find('.field');
+ if (($(this).val() == "") || $(this).val() == "GPU-Passthrough") {
+ $form.find('[rel=vgpuType]').hide();
+ } else if ($(this).val() == "VGPU") {
+ $form.find('[rel=vgpuType]').css('display', 'block');
+ }
+ });
+ }
+ },
+
+ vgpuType: {
+ label: 'VGPU Type',
+ select: function(args) {
+ var items = [];
+ items.push({
+ id: '',
+ description: ''
+ });
+ items.push({
+ id: 'GRID K100',
+ description: 'GRID K100'
+ });
+ items.push({
+ id: 'GRID K140Q',
+ description: 'GRID K140Q'
+ });
+ items.push({
+ id: 'GRID K200',
+ description: 'GRID K200'
+ });
+ items.push({
+ id: 'GRID K240Q',
+ description: 'GRID K240Q'
+ });
+ items.push({
+ id: 'GRID K260Q',
+ description: 'GRID K260Q'
+ });
+ args.response.success({
+ data: items
+ });
+ }
+ },
+
domainId: {
label: 'label.domain',
docID: 'helpComputeOfferingDomain',
@@ -428,6 +493,14 @@
array1.push("&serviceofferingdetails[0].ImplicitDedicationMode" + "=" + args.data.plannerMode);
}
+ if (args.data.pciDevice != "") {
+ array1.push("&serviceofferingdetails[1].pciDevice" + "=" + args.data.pciDevice);
+ }
+
+ if (args.data.pciDevice == "VGPU") {
+ array1.push("&serviceofferingdetails[2].vgpuType" + "=" + args.data.vgpuType);
+ }
+
if (args.data.networkRate != null && args.data.networkRate.length > 0) {
$.extend(data, {
networkrate: args.data.networkRate
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c7d31fe2/ui/scripts/instances.js
----------------------------------------------------------------------
diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js
index e5b2e85..10d2591 100644
--- a/ui/scripts/instances.js
+++ b/ui/scripts/instances.js
@@ -1804,7 +1804,9 @@
memory: {
label: 'label.memory.mb'
},
-
+ vgpu: {
+ label: 'VGPU'
+ },
haenable: {
label: 'label.ha.enabled',
converter: cloudStack.converters.toBooleanText