Feature: Add support for GPU with KVM hosts (#11143)

This PR allows attaching of GPU devices via PCI, mdev or VF to an Instance for KVM.

It allows the operator to discover the GPU devices on the KVM host and create a Compute Offering with GPU support based on the available GPU devices on the host. Once the operator has created the Compute offering, it can be used by users to launch Instances with GPU devices.
This commit is contained in:
Vishesh 2025-07-29 13:46:24 +05:30 committed by GitHub
parent b92c1965b9
commit f6ad184ea2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
183 changed files with 16229 additions and 605 deletions

View File

@ -140,6 +140,7 @@ jobs:
smoke/test_vm_deployment_planner
smoke/test_vm_strict_host_tags
smoke/test_vm_schedule
smoke/test_deploy_vgpu_enabled_vm
smoke/test_vm_life_cycle
smoke/test_vm_lifecycle_unmanage_import
smoke/test_vm_snapshot_kvm

View File

@ -221,6 +221,15 @@ public class AgentProperties{
*/
public static final Property<String> AGENT_HOOKS_LIBVIRT_VM_XML_TRANSFORMER_SCRIPT = new Property<>("agent.hooks.libvirt_vm_xml_transformer.script", "libvirt-vm-xml-transformer.groovy");
/**
* This property is used with the agent.hooks.basedir property to define the Libvirt VM XML transformer shell script.<br>
* The shell script is used to execute the Libvirt VM XML transformer script.<br>
* For more information see the agent.properties file.<br>
* Data type: String.<br>
* Default value: <code>libvirt-vm-xml-transformer.sh</code>
*/
public static final Property<String> AGENT_HOOKS_LIBVIRT_VM_XML_TRANSFORMER_SHELL_SCRIPT = new Property<>("agent.hooks.libvirt_vm_xml_transformer.shell_script", "libvirt-vm-xml-transformer.sh");
/**
* This property is used with the agent.hooks.basedir and agent.hooks.libvirt_vm_xml_transformer.script properties to define the Libvirt VM XML transformer method.<br>
* Libvirt XML transformer hook does XML-to-XML transformation.<br>
@ -241,6 +250,15 @@ public class AgentProperties{
*/
public static final Property<String> AGENT_HOOKS_LIBVIRT_VM_ON_START_SCRIPT = new Property<>("agent.hooks.libvirt_vm_on_start.script", "libvirt-vm-state-change.groovy");
/**
* This property is used with the agent.hooks.basedir property to define the Libvirt VM on start shell script.<br>
* The shell script is used to execute the Libvirt VM on start script.<br>
* For more information see the agent.properties file.<br>
* Data type: String.<br>
* Default value: <code>libvirt-vm-state-change.sh</code>
*/
public static final Property<String> AGENT_HOOKS_LIBVIRT_VM_ON_START_SHELL_SCRIPT = new Property<>("agent.hooks.libvirt_vm_on_start.shell_script", "libvirt-vm-state-change.sh");
/**
* This property is used with the agent.hooks.basedir and agent.hooks.libvirt_vm_on_start.script properties to define the Libvirt VM on start method.<br>
* The hook is called right after Libvirt successfully launched the VM.<br>
@ -260,6 +278,15 @@ public class AgentProperties{
*/
public static final Property<String> AGENT_HOOKS_LIBVIRT_VM_ON_STOP_SCRIPT = new Property<>("agent.hooks.libvirt_vm_on_stop.script", "libvirt-vm-state-change.groovy");
/**
* This property is used with the agent.hooks.basedir property to define the Libvirt VM on stop shell script.<br>
* The shell script is used to execute the Libvirt VM on stop script.<br>
* For more information see the agent.properties file.<br>
* Data type: String.<br>
* Default value: <code>libvirt-vm-state-change.sh</code>
*/
public static final Property<String> AGENT_HOOKS_LIBVIRT_VM_ON_STOP_SHELL_SCRIPT = new Property<>("agent.hooks.libvirt_vm_on_stop.shell_script", "libvirt-vm-state-change.sh");
/**
* This property is used with the agent.hooks.basedir and agent.hooks.libvirt_vm_on_stop.script properties to define the Libvirt VM on stop method.<br>
* The hook is called right after libvirt successfully stopped the VM.<br>

View File

@ -15,10 +15,24 @@
// specific language governing permissions and limitations
// under the License.
package com.cloud.agent.api;
import org.apache.cloudstack.gpu.GpuDevice;
public class VgpuTypesInfo {
private boolean passthroughEnabled = true;
private GpuDevice.DeviceType deviceType;
private String parentBusAddress;
private String busAddress;
private String numaNode;
private String pciRoot;
private String deviceId;
private String deviceName;
private String vendorId;
private String vendorName;
private String modelName;
private String groupName;
private String vmName;
private Long maxHeads;
private Long videoRam;
private Long maxResolutionX;
@ -26,6 +40,7 @@ public class VgpuTypesInfo {
private Long maxVgpuPerGpu;
private Long remainingCapacity;
private Long maxCapacity;
private boolean display = false;
public String getModelName() {
return modelName;
@ -39,22 +54,42 @@ public class VgpuTypesInfo {
return videoRam;
}
public void setVideoRam(Long videoRam) {
this.videoRam = videoRam;
}
public Long getMaxHeads() {
return maxHeads;
}
public void setMaxHeads(Long maxHeads) {
this.maxHeads = maxHeads;
}
public Long getMaxResolutionX() {
return maxResolutionX;
}
public void setMaxResolutionX(Long maxResolutionX) {
this.maxResolutionX = maxResolutionX;
}
public Long getMaxResolutionY() {
return maxResolutionY;
}
public void setMaxResolutionY(Long maxResolutionY) {
this.maxResolutionY = maxResolutionY;
}
public Long getMaxVpuPerGpu() {
return maxVgpuPerGpu;
}
public void setMaxVgpuPerGpu(Long maxVgpuPerGpu) {
this.maxVgpuPerGpu = maxVgpuPerGpu;
}
public Long getRemainingCapacity() {
return remainingCapacity;
}
@ -71,8 +106,133 @@ public class VgpuTypesInfo {
this.maxCapacity = maxCapacity;
}
public VgpuTypesInfo(String groupName, String modelName, Long videoRam, Long maxHeads, Long maxResolutionX, Long maxResolutionY, Long maxVgpuPerGpu,
Long remainingCapacity, Long maxCapacity) {
public boolean isPassthroughEnabled() {
return passthroughEnabled;
}
public void setPassthroughEnabled(boolean passthroughEnabled) {
this.passthroughEnabled = passthroughEnabled;
}
public GpuDevice.DeviceType getDeviceType() {
return deviceType;
}
public void setDeviceType(GpuDevice.DeviceType deviceType) {
this.deviceType = deviceType;
}
public String getParentBusAddress() {
return parentBusAddress;
}
public void setParentBusAddress(String parentBusAddress) {
this.parentBusAddress = parentBusAddress;
}
public String getBusAddress() {
return busAddress;
}
public void setBusAddress(String busAddress) {
this.busAddress = busAddress;
}
public String getNumaNode() {
return numaNode;
}
public void setNumaNode(String numaNode) {
this.numaNode = numaNode;
}
public String getPciRoot() {
return pciRoot;
}
public void setPciRoot(String pciRoot) {
this.pciRoot = pciRoot;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getDeviceName() {
return deviceName;
}
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
public String getVendorId() {
return vendorId;
}
public void setVendorId(String vendorId) {
this.vendorId = vendorId;
}
public String getVendorName() {
return vendorName;
}
public void setVendorName(String vendorName) {
this.vendorName = vendorName;
}
public String getVmName() {
return vmName;
}
public void setVmName(String vmName) {
this.vmName = vmName;
}
public boolean isDisplay() {
return display;
}
public void setDisplay(boolean display) {
this.display = display;
}
public VgpuTypesInfo(GpuDevice.DeviceType deviceType, String groupName, String modelName, String busAddress,
String vendorId, String vendorName, String deviceId, String deviceName, String numaNode, String pciRoot
) {
this.deviceType = deviceType;
this.groupName = groupName;
this.modelName = modelName;
this.busAddress = busAddress;
this.deviceId = deviceId;
this.deviceName = deviceName;
this.vendorId = vendorId;
this.vendorName = vendorName;
this.numaNode = numaNode;
this.pciRoot = pciRoot;
}
public VgpuTypesInfo(GpuDevice.DeviceType deviceType, String groupName, String modelName, String busAddress,
String vendorId, String vendorName, String deviceId, String deviceName
) {
this.deviceType = deviceType;
this.groupName = groupName;
this.modelName = modelName;
this.busAddress = busAddress;
this.deviceId = deviceId;
this.deviceName = deviceName;
this.vendorId = vendorId;
this.vendorName = vendorName;
}
public VgpuTypesInfo(String groupName, String modelName, Long videoRam, Long maxHeads, Long maxResolutionX,
Long maxResolutionY, Long maxVgpuPerGpu, Long remainingCapacity, Long maxCapacity
) {
this.groupName = groupName;
this.modelName = modelName;
this.videoRam = videoRam;

View File

@ -16,7 +16,9 @@
// under the License.
package com.cloud.agent.api.to;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import com.cloud.agent.api.VgpuTypesInfo;
@ -24,9 +26,23 @@ public class GPUDeviceTO {
private String gpuGroup;
private String vgpuType;
private int gpuCount;
private HashMap<String, HashMap<String, VgpuTypesInfo>> groupDetails = new HashMap<String, HashMap<String, VgpuTypesInfo>>();
private List<VgpuTypesInfo> gpuDevices = new ArrayList<>();
public GPUDeviceTO( String gpuGroup, String vgpuType, HashMap<String, HashMap<String, VgpuTypesInfo>> groupDetails) {
public GPUDeviceTO(String gpuGroup, String vgpuType, int gpuCount,
HashMap<String, HashMap<String, VgpuTypesInfo>> groupDetails,
List<VgpuTypesInfo> gpuDevices) {
this.gpuGroup = gpuGroup;
this.vgpuType = vgpuType;
this.groupDetails = groupDetails;
this.gpuCount = gpuCount;
this.gpuDevices = gpuDevices;
}
public GPUDeviceTO(String gpuGroup, String vgpuType,
HashMap<String, HashMap<String, VgpuTypesInfo>> groupDetails) {
this.gpuGroup = gpuGroup;
this.vgpuType = vgpuType;
this.groupDetails = groupDetails;
@ -48,6 +64,14 @@ public class GPUDeviceTO {
this.vgpuType = vgpuType;
}
public int getGpuCount() {
return gpuCount;
}
public void setGpuCount(int gpuCount) {
this.gpuCount = gpuCount;
}
public HashMap<String, HashMap<String, VgpuTypesInfo>> getGroupDetails() {
return groupDetails;
}
@ -56,4 +80,11 @@ public class GPUDeviceTO {
this.groupDetails = groupDetails;
}
public List<VgpuTypesInfo> getGpuDevices() {
return gpuDevices;
}
public void setGpuDevices(List<VgpuTypesInfo> gpuDevices) {
this.gpuDevices = gpuDevices;
}
}

View File

@ -37,7 +37,8 @@ public interface Resource {
backup("backup", 12),
backup_storage("backup_storage", 13),
bucket("bucket", 14),
object_storage("object_storage", 15);
object_storage("object_storage", 15),
gpu("gpu", 16);
private String name;
private int ordinal;

View File

@ -31,6 +31,9 @@ import org.apache.cloudstack.config.Configuration;
import org.apache.cloudstack.datacenter.DataCenterIpv4GuestSubnet;
import org.apache.cloudstack.extension.Extension;
import org.apache.cloudstack.extension.ExtensionCustomAction;
import org.apache.cloudstack.gpu.GpuCard;
import org.apache.cloudstack.gpu.GpuDevice;
import org.apache.cloudstack.gpu.VgpuProfile;
import org.apache.cloudstack.ha.HAConfig;
import org.apache.cloudstack.network.BgpPeer;
import org.apache.cloudstack.network.Ipv4GuestSubnetNetworkMap;
@ -378,6 +381,21 @@ public class EventTypes {
public static final String EVENT_DISK_OFFERING_EDIT = "DISK.OFFERING.EDIT";
public static final String EVENT_DISK_OFFERING_DELETE = "DISK.OFFERING.DELETE";
// GPU Cards
public static final String EVENT_GPU_CARD_CREATE = "GPU.CARD.CREATE";
public static final String EVENT_GPU_CARD_EDIT = "GPU.CARD.EDIT";
public static final String EVENT_GPU_CARD_DELETE = "GPU.CARD.DELETE";
// vGPU Profile
public static final String EVENT_VGPU_PROFILE_CREATE = "VGPU.PROFILE.CREATE";
public static final String EVENT_VGPU_PROFILE_EDIT = "VGPU.PROFILE.EDIT";
public static final String EVENT_VGPU_PROFILE_DELETE = "VGPU.PROFILE.DELETE";
// GPU Devices
public static final String EVENT_GPU_DEVICE_CREATE = "GPU.DEVICE.CREATE";
public static final String EVENT_GPU_DEVICE_EDIT = "GPU.DEVICE.EDIT";
public static final String EVENT_GPU_DEVICE_DELETE = "GPU.DEVICE.DELETE";
// Network offerings
public static final String EVENT_NETWORK_OFFERING_CREATE = "NETWORK.OFFERING.CREATE";
public static final String EVENT_NETWORK_OFFERING_ASSIGN = "NETWORK.OFFERING.ASSIGN";
@ -1026,6 +1044,21 @@ public class EventTypes {
entityEventDetails.put(EVENT_DISK_OFFERING_EDIT, DiskOffering.class);
entityEventDetails.put(EVENT_DISK_OFFERING_DELETE, DiskOffering.class);
// GPU Cards
entityEventDetails.put(EVENT_GPU_CARD_CREATE, GpuCard.class);
entityEventDetails.put(EVENT_GPU_CARD_EDIT, GpuCard.class);
entityEventDetails.put(EVENT_GPU_CARD_DELETE, GpuCard.class);
// vGPU Profiles
entityEventDetails.put(EVENT_VGPU_PROFILE_CREATE, VgpuProfile.class);
entityEventDetails.put(EVENT_VGPU_PROFILE_EDIT, VgpuProfile.class);
entityEventDetails.put(EVENT_VGPU_PROFILE_DELETE, VgpuProfile.class);
// GPU Devices
entityEventDetails.put(EVENT_GPU_DEVICE_CREATE, GpuDevice.class);
entityEventDetails.put(EVENT_GPU_DEVICE_EDIT, GpuDevice.class);
entityEventDetails.put(EVENT_GPU_DEVICE_DELETE, GpuDevice.class);
// Network offerings
entityEventDetails.put(EVENT_NETWORK_OFFERING_CREATE, NetworkOffering.class);
entityEventDetails.put(EVENT_NETWORK_OFFERING_ASSIGN, NetworkOffering.class);

View File

@ -142,4 +142,8 @@ public interface ServiceOffering extends InfrastructureEntity, InternalIdentity,
Boolean getDiskOfferingStrictness();
void setDiskOfferingStrictness(boolean diskOfferingStrictness);
Long getVgpuProfileId();
Integer getGpuCount();
}

View File

@ -50,8 +50,14 @@ public interface ResourceLimitService {
"The default maximum number of projects that can be created for an account",false);
static final ConfigKey<Long> DefaultMaxDomainProjects = new ConfigKey<>("Domain Defaults",Long.class,"max.domain.projects","50",
"The default maximum number of projects that can be created for a domain",false);
static final ConfigKey<Long> DefaultMaxAccountGpus = new ConfigKey<>("Account Defaults",Long.class,"max.account.gpus","20",
"The default maximum number of GPU devices that can be used for an account", false);
static final ConfigKey<Long> DefaultMaxDomainGpus = new ConfigKey<>("Domain Defaults",Long.class,"max.domain.gpus","20",
"The default maximum number of GPU devices that can be used for a domain", false);
static final ConfigKey<Long> DefaultMaxProjectGpus = new ConfigKey<>("Project Defaults",Long.class,"max.project.gpus","20",
"The default maximum number of GPU devices that can be used for a project", false);
static final List<ResourceType> HostTagsSupportingTypes = List.of(ResourceType.user_vm, ResourceType.cpu, ResourceType.memory);
static final List<ResourceType> HostTagsSupportingTypes = List.of(ResourceType.user_vm, ResourceType.cpu, ResourceType.memory, ResourceType.gpu);
static final List<ResourceType> StorageTagsSupportingTypes = List.of(ResourceType.volume, ResourceType.primary_storage);
/**
@ -284,4 +290,8 @@ public interface ResourceLimitService {
void incrementVmMemoryResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long memory);
void decrementVmMemoryResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long memory);
void checkVmGpuResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long gpu) throws ResourceAllocationException;
void incrementVmGpuResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long gpu);
void decrementVmGpuResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Long gpu);
}

View File

@ -69,6 +69,7 @@ public class ApiConstants {
public static final String BOOTABLE = "bootable";
public static final String BIND_DN = "binddn";
public static final String BIND_PASSWORD = "bindpass";
public static final String BUS_ADDRESS = "busaddress";
public static final String BYTES_READ_RATE = "bytesreadrate";
public static final String BYTES_READ_RATE_MAX = "bytesreadratemax";
public static final String BYTES_READ_RATE_MAX_LENGTH = "bytesreadratemaxlength";
@ -162,6 +163,7 @@ public class ApiConstants {
public static final String DESTINATION_ZONE_ID = "destzoneid";
public static final String DETAILS = "details";
public static final String DEVICE_ID = "deviceid";
public static final String DEVICE_NAME = "devicename";
public static final String DIRECT_DOWNLOAD = "directdownload";
public static final String DISK = "disk";
public static final String DISK_OFFERING_ID = "diskofferingid";
@ -388,6 +390,7 @@ public class ApiConstants {
public static final String NEW_START_IP = "newstartip";
public static final String NEW_END_IP = "newendip";
public static final String KUBERNETES_NODE_VERSION = "kubernetesnodeversion";
public static final String NUMA_NODE = "numanode";
public static final String NUM_RETRIES = "numretries";
public static final String OFFER_HA = "offerha";
public static final String OS_DISTRIBUTION = "osdistribution";
@ -404,6 +407,13 @@ public class ApiConstants {
public static final String OS_TYPE_ID = "ostypeid";
public static final String OS_DISPLAY_NAME = "osdisplayname";
public static final String OS_NAME_FOR_HYPERVISOR = "osnameforhypervisor";
public static final String GPU_CARD_ID = "gpucardid";
public static final String GPU_CARD_NAME = "gpucardname";
public static final String GPU_COUNT = "gpucount";
public static final String GPU_DISPLAY = "gpudisplay";
public static final String GPU_DEVICE_TYPE = "gpudevicetype";
public static final String GPU_ENABLED = "gpuenabled";
public static final String MAX_VGPU_PER_PHYSICAL_GPU = "maxvgpuperphysicalgpu";
public static final String GUEST_OS_LIST = "guestoslist";
public static final String GUEST_OS_COUNT = "guestoscount";
public static final String OS_MAPPING_CHECK_ENABLED = "osmappingcheckenabled";
@ -415,9 +425,11 @@ public class ApiConstants {
public static final String PARENT = "parent";
public static final String PARENT_ID = "parentid";
public static final String PARENT_DOMAIN_ID = "parentdomainid";
public static final String PARENT_GPU_DEVICE_ID = "parentgpudeviceid";
public static final String PARENT_SUBNET = "parentsubnet";
public static final String PARENT_TEMPLATE_ID = "parenttemplateid";
public static final String PASSWORD = "password";
public static final String PCI_ROOT = "pciroot";
public static final String CURRENT_PASSWORD = "currentpassword";
public static final String SHOULD_UPDATE_PASSWORD = "update_passwd_on_host";
public static final String PASSWORD_ENABLED = "passwordenabled";
@ -588,6 +600,10 @@ public class ApiConstants {
public static final String VALIDATION_FORMAT = "validationformat";
public static final String VALUE = "value";
public static final String VALUE_OPTIONS = "valueoptions";
public static final String VENDOR_ID = "vendorid";
public static final String VENDOR_NAME = "vendorname";
public static final String VGPU_PROFILE_ID = "vgpuprofileid";
public static final String VGPU_PROFILE_NAME = "vgpuprofilename";
public static final String VIRTUAL_MACHINE = "virtualmachine";
public static final String VIRTUAL_MACHINE_ID = "virtualmachineid";
public static final String VIRTUAL_MACHINE_IDS = "virtualmachineids";

View File

@ -39,6 +39,7 @@ import org.apache.cloudstack.affinity.AffinityGroupService;
import org.apache.cloudstack.alert.AlertService;
import org.apache.cloudstack.annotation.AnnotationService;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.gpu.GpuService;
import org.apache.cloudstack.network.RoutedIpv4Manager;
import org.apache.cloudstack.network.lb.ApplicationLoadBalancerService;
import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService;
@ -131,6 +132,8 @@ public abstract class BaseCmd {
@Inject
public UserVmService _userVmService;
@Inject
public GpuService gpuService;
@Inject
public ManagementService _mgr;
@Inject
public StorageService _storageService;

View File

@ -0,0 +1,122 @@
// 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.api.command.admin.gpu;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.user.Account;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.GpuCardResponse;
import org.apache.cloudstack.gpu.GpuCard;
@APICommand(name = "createGpuCard", description = "Creates a GPU card definition in the system",
responseObject = GpuCardResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
since = "4.21.0")
public class CreateGpuCardCmd extends BaseCmd {
/// //////////////////////////////////////////////////
/// ///////////// API parameters /////////////////////
/// //////////////////////////////////////////////////
@Parameter(name = ApiConstants.DEVICE_ID, type = CommandType.STRING, required = true,
description = "the device ID of the GPU card")
private String deviceId;
@Parameter(name = ApiConstants.DEVICE_NAME, type = CommandType.STRING, required = true,
description = "the device name of the GPU card")
private String deviceName;
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true,
description = "the display name of the GPU card")
private String name;
@Parameter(name = ApiConstants.VENDOR_NAME, type = CommandType.STRING, required = true,
description = "the vendor name of the GPU card")
private String vendorName;
@Parameter(name = ApiConstants.VENDOR_ID, type = CommandType.STRING, required = true,
description = "the vendor ID of the GPU card")
private String vendorId;
// Optional parameters for the passthrough vGPU profile display properties
@Parameter(name = ApiConstants.VIDEORAM, type = CommandType.LONG,
description = "the video RAM size in MB for the passthrough vGPU profile")
private Long videoRam;
/// //////////////////////////////////////////////////
/// //////////////// Accessors ///////////////////////
/// //////////////////////////////////////////////////
public String getDeviceId() {
return deviceId;
}
public String getDeviceName() {
return deviceName;
}
public String getName() {
return name;
}
public String getVendorName() {
return vendorName;
}
public String getVendorId() {
return vendorId;
}
public Long getVideoRam() {
return videoRam;
}
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException,
ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
try {
GpuCard gpuCard = gpuService.createGpuCard(this);
if (gpuCard != null) {
GpuCardResponse response = new GpuCardResponse(gpuCard);
response.setResponseName(getCommandName());
setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create GPU card");
}
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create GPU card: " + e.getMessage());
}
}
/// //////////////////////////////////////////////////
/// //////////// API Implementation///////////////////
/// //////////////////////////////////////////////////
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,123 @@
// 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.GpuCardResponse;
import org.apache.cloudstack.api.response.GpuDeviceResponse;
import org.apache.cloudstack.api.response.HostResponse;
import org.apache.cloudstack.api.response.VgpuProfileResponse;
import org.apache.cloudstack.gpu.GpuDevice;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils;
@APICommand(name = "createGpuDevice", description = "Creates a GPU device manually on a host",
responseObject = GpuDeviceResponse.class, since = "4.21.0", requestHasSensitiveInfo = false,
responseHasSensitiveInfo = false, authorized = {RoleType.Admin})
public class CreateGpuDeviceCmd extends BaseCmd {
@Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class, required = true,
description = "ID of the host where the GPU device is located")
private Long hostId;
@Parameter(name = ApiConstants.BUS_ADDRESS, type = CommandType.STRING, required = true,
description = "PCI bus address of the GPU device (e.g., 0000:01:00.0) or UUID for MDEV devices.")
private String busAddress;
@Parameter(name = ApiConstants.GPU_CARD_ID, type = CommandType.UUID, entityType = GpuCardResponse.class,
required = true, description = "ID of the GPU card type")
private Long gpuCardId;
@Parameter(name = ApiConstants.VGPU_PROFILE_ID, type = CommandType.UUID, entityType = VgpuProfileResponse.class,
required = true, description = "ID of the vGPU profile")
private Long vgpuProfileId;
@Parameter(name = ApiConstants.TYPE, type = CommandType.STRING,
description = "Type of GPU device (PCI, MDEV, VGPUOnly). Defaults to PCI.")
private String type;
@Parameter(name = ApiConstants.PARENT_GPU_DEVICE_ID, type = CommandType.UUID, entityType = GpuDeviceResponse.class,
description = "ID of the parent GPU device (for virtual GPU devices)")
private Long parentGpuDeviceId;
@Parameter(name = ApiConstants.NUMA_NODE, type = CommandType.STRING,
description = "NUMA node of the GPU device (e.g., 0, 1, etc.). This is optional and can be used to "
+ "specify the NUMA node for the GPU device which is used during allocation. Defaults to -1")
private String numaNode;
public Long getHostId() {
return hostId;
}
public String getBusAddress() {
return busAddress;
}
public Long getGpuCardId() {
return gpuCardId;
}
public Long getVgpuProfileId() {
return vgpuProfileId;
}
public GpuDevice.DeviceType getType() {
GpuDevice.DeviceType deviceType = GpuDevice.DeviceType.PCI;
if (StringUtils.isNotBlank(type)) {
deviceType = EnumUtils.getEnumIgnoreCase(GpuDevice.DeviceType.class, type);
if (deviceType == null) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid GPU device type: " + type);
}
}
return deviceType;
}
public Long getParentGpuDeviceId() {
return parentGpuDeviceId;
}
public String getNumaNode() {
if (StringUtils.isBlank(numaNode)) {
return "-1"; // Default value for NUMA node
}
return numaNode;
}
@Override
public void execute() {
try {
GpuDeviceResponse response = gpuService.createGpuDevice(this);
response.setResponseName(getCommandName());
setResponseObject(response);
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,131 @@
// 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.GpuCardResponse;
import org.apache.cloudstack.api.response.VgpuProfileResponse;
@APICommand(name = "createVgpuProfile", description = "Creates a vGPU profile in the system",
responseObject = VgpuProfileResponse.class, requestHasSensitiveInfo = false,
responseHasSensitiveInfo = false, since = "4.21.0", authorized = {RoleType.Admin})
public class CreateVgpuProfileCmd extends BaseCmd {
/// //////////////////////////////////////////////////
/// ///////////// API parameters /////////////////////
/// //////////////////////////////////////////////////
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true,
description = "the name of the vGPU profile")
private String name;
@Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING,
description = "the description of the vGPU profile")
private String description;
@Parameter(name = ApiConstants.GPU_CARD_ID, type = CommandType.UUID, entityType = GpuCardResponse.class,
required = true, description = "the GPU card ID associated with this GPU device")
private Long cardId;
@Parameter(name = ApiConstants.MAX_VGPU_PER_PHYSICAL_GPU, type = CommandType.LONG,
description = "Max vGPU per physical GPU. This is used to calculate capacity.")
private Long maxVgpuPerPgpu;
@Parameter(name = ApiConstants.VIDEORAM, type = CommandType.LONG,
description = "the video RAM size in MB")
private Long videoRam;
@Parameter(name = ApiConstants.MAXHEADS, type = CommandType.LONG,
description = "the maximum number of display heads")
private Long maxHeads;
@Parameter(name = ApiConstants.MAXRESOLUTIONX, type = CommandType.LONG,
description = "the maximum X resolution")
private Long maxResolutionX;
@Parameter(name = ApiConstants.MAXRESOLUTIONY, type = CommandType.LONG,
description = "the maximum Y resolution")
private Long maxResolutionY;
/// //////////////////////////////////////////////////
/// //////////////// Accessors ///////////////////////
/// //////////////////////////////////////////////////
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public Long getCardId() {
return cardId;
}
public Long getMaxVgpuPerPgpu() {
return maxVgpuPerPgpu;
}
public Long getVideoRam() {
return videoRam;
}
public Long getMaxHeads() {
return maxHeads;
}
public Long getMaxResolutionX() {
return maxResolutionX;
}
public Long getMaxResolutionY() {
return maxResolutionY;
}
@Override
public void execute() {
try {
VgpuProfileResponse response = gpuService.createVgpuProfile(this);
if (response != null) {
setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create vGPU profile");
}
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR,
"Failed to create vGPU profile: " + e.getMessage());
}
}
/// //////////////////////////////////////////////////
/// //////////// API Implementation///////////////////
/// //////////////////////////////////////////////////
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,75 @@
// 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.GpuCardResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
@APICommand(name = "deleteGpuCard", description = "Deletes a GPU card definition from the system",
responseObject = SuccessResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
since = "4.21.0", authorized = {RoleType.Admin})
public class DeleteGpuCardCmd extends BaseCmd {
/// //////////////////////////////////////////////////
/// ///////////// API parameters /////////////////////
/// //////////////////////////////////////////////////
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = GpuCardResponse.class, required = true,
description = "the ID of the GPU card")
private Long id;
/// //////////////////////////////////////////////////
/// //////////////// Accessors ///////////////////////
/// //////////////////////////////////////////////////
public Long getId() {
return id;
}
@Override
public void execute() {
try {
boolean success = gpuService.deleteGpuCard(this);
if (success) {
SuccessResponse response = new SuccessResponse(getCommandName());
setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete GPU card");
}
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete GPU card: " + e.getMessage());
}
}
/// //////////////////////////////////////////////////
/// //////////// API Implementation///////////////////
/// //////////////////////////////////////////////////
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,78 @@
// 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.GpuDeviceResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import java.util.List;
@APICommand(name = "deleteGpuDevice", description = "Deletes a vGPU profile from the system",
responseObject = SuccessResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
since = "4.21.0", authorized = {RoleType.Admin})
public class DeleteGpuDeviceCmd extends BaseCmd {
/// //////////////////////////////////////////////////
/// ///////////// API parameters /////////////////////
/// //////////////////////////////////////////////////
@Parameter(name = ApiConstants.IDS, type = CommandType.LIST, collectionType = CommandType.UUID,
entityType = GpuDeviceResponse.class, required = true,
description = "comma separated list of IDs of the GPU device")
private List<Long> ids;
/// //////////////////////////////////////////////////
/// //////////////// Accessors ///////////////////////
/// //////////////////////////////////////////////////
public List<Long> getIds() {
return ids;
}
@Override
public void execute() {
try {
boolean success = gpuService.deleteGpuDevices(this);
if (success) {
SuccessResponse response = new SuccessResponse(getCommandName());
setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete vGPU profile");
}
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR,
"Failed to delete vGPU profile: " + e.getMessage());
}
}
/// //////////////////////////////////////////////////
/// //////////// API Implementation///////////////////
/// //////////////////////////////////////////////////
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,76 @@
// 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.api.response.VgpuProfileResponse;
@APICommand(name = "deleteVgpuProfile", description = "Deletes a vGPU profile from the system",
responseObject = SuccessResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
since = "4.21.0", authorized = {RoleType.Admin})
public class DeleteVgpuProfileCmd extends BaseCmd {
/// //////////////////////////////////////////////////
/// ///////////// API parameters /////////////////////
/// //////////////////////////////////////////////////
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = VgpuProfileResponse.class, required = true,
description = "the ID of the vGPU profile")
private Long id;
/// //////////////////////////////////////////////////
/// //////////////// Accessors ///////////////////////
/// //////////////////////////////////////////////////
public Long getId() {
return id;
}
@Override
public void execute() {
try {
boolean success = gpuService.deleteVgpuProfile(this);
if (success) {
SuccessResponse response = new SuccessResponse(getCommandName());
setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete vGPU profile");
}
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR,
"Failed to delete vGPU profile: " + e.getMessage());
}
}
/// //////////////////////////////////////////////////
/// //////////// API Implementation///////////////////
/// //////////////////////////////////////////////////
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,63 @@
// 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.api.command.admin.gpu;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.GpuDeviceResponse;
import org.apache.cloudstack.api.response.HostResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.context.CallContext;
@APICommand(name = "discoverGpuDevices", description = "Discovers available GPU devices on a host",
responseObject = GpuDeviceResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
since = "4.21.0", authorized = {RoleType.Admin})
public class DiscoverGpuDevicesCmd extends BaseListCmd {
/// //////////////////////////////////////////////////
/// ///////////// API parameters /////////////////////
/// //////////////////////////////////////////////////
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = HostResponse.class, required = true,
description = "ID of the host")
private Long id;
/// //////////////////////////////////////////////////
/// //////////// API Implementation //////////////////
/// //////////////////////////////////////////////////
@Override
public void execute() {
CallContext.current().setEventDetails("Discovering GPU Devices on host id: " + getId());
ListResponse<GpuDeviceResponse> response = gpuService.discoverGpuDevices(this);
response.setResponseName(getCommandName());
setResponseObject(response);
}
/// //////////////////////////////////////////////////
/// //////////////// Accessors ///////////////////////
/// //////////////////////////////////////////////////
public Long getId() {
return id;
}
}

View File

@ -0,0 +1,74 @@
// 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.api.command.admin.gpu;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ResponseObject;
import org.apache.cloudstack.api.command.admin.AdminCmd;
import org.apache.cloudstack.api.command.user.gpu.ListGpuDevicesCmd;
import org.apache.cloudstack.api.response.GpuCardResponse;
import org.apache.cloudstack.api.response.GpuDeviceResponse;
import org.apache.cloudstack.api.response.HostResponse;
import org.apache.cloudstack.api.response.VgpuProfileResponse;
@APICommand(name = "listGpuDevices", description = "Lists all available GPU devices",
responseView = ResponseObject.ResponseView.Full,
responseObject = GpuDeviceResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
since = "4.21.0")
public class ListGpuDevicesCmdByAdmin extends ListGpuDevicesCmd implements AdminCmd {
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = GpuDeviceResponse.class,
description = "ID of the GPU device")
private Long id;
@Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class,
description = "the host ID where the GPU device is attached")
private Long hostId;
@Parameter(name = ApiConstants.GPU_CARD_ID, type = CommandType.UUID, entityType = GpuCardResponse.class,
description = "the GPU card ID associated with the GPU device")
private Long gpuCardId;
@Parameter(name = ApiConstants.VGPU_PROFILE_ID, type = CommandType.UUID, entityType = VgpuProfileResponse.class,
description = "the vGPU profile ID assigned to the GPU device")
private Long vgpuProfileId;
/// //////////////////////////////////////////////////
/// //////////////// Accessors ///////////////////////
/// //////////////////////////////////////////////////
public Long getId() {
return id;
}
public Long getHostId() {
return hostId;
}
public Long getGpuCardId() {
return gpuCardId;
}
public Long getVgpuProfileId() {
return vgpuProfileId;
}
}

View File

@ -0,0 +1,78 @@
// 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.GpuDeviceResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import java.util.List;
@APICommand(name = "manageGpuDevice", description = "Manages a GPU device", responseObject = SuccessResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.21.0",
authorized = {RoleType.Admin})
public class ManageGpuDeviceCmd extends BaseCmd {
/// //////////////////////////////////////////////////
/// ///////////// API parameters /////////////////////
/// //////////////////////////////////////////////////
@Parameter(name = ApiConstants.IDS, type = CommandType.LIST, collectionType = CommandType.UUID,
entityType = GpuDeviceResponse.class, required = true,
description = "comma separated list of IDs of the GPU device")
private List<Long> ids;
/// //////////////////////////////////////////////////
/// //////////////// Accessors ///////////////////////
/// //////////////////////////////////////////////////
public List<Long> getIds() {
return ids;
}
@Override
public void execute() {
try {
if (gpuService.enableGpuDevice(this)) {
SuccessResponse response = new SuccessResponse();
response.setResponseName(getCommandName());
setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to enable GPU device");
}
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to enable GPU device: " + e.getMessage());
}
}
/// //////////////////////////////////////////////////
/// //////////// API Implementation///////////////////
/// //////////////////////////////////////////////////
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,79 @@
// 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.GpuDeviceResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import java.util.List;
@APICommand(name = "unmanageGpuDevice", description = "Unmanage a GPU device", responseObject = SuccessResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.21.0",
authorized = {RoleType.Admin})
public class UnmanageGpuDeviceCmd extends BaseCmd {
/// //////////////////////////////////////////////////
/// ///////////// API parameters /////////////////////
/// //////////////////////////////////////////////////
@Parameter(name = ApiConstants.IDS, type = CommandType.LIST, collectionType = CommandType.UUID,
entityType = GpuDeviceResponse.class, required = true,
description = "comma separated list of IDs of the GPU device")
private List<Long> ids;
/// //////////////////////////////////////////////////
/// //////////////// Accessors ///////////////////////
/// //////////////////////////////////////////////////
public List<Long> getIds() {
return ids;
}
@Override
public void execute() {
try {
if (gpuService.disableGpuDevice(this)) {
SuccessResponse response = new SuccessResponse();
response.setResponseName(getCommandName());
setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to disable GPU device");
}
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR,
"Failed to disable GPU device: " + e.getMessage());
}
}
/// //////////////////////////////////////////////////
/// //////////// API Implementation///////////////////
/// //////////////////////////////////////////////////
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,99 @@
// 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.GpuCardResponse;
import org.apache.cloudstack.gpu.GpuCard;
@APICommand(name = "updateGpuCard", description = "Updates a GPU card definition in the system",
responseObject = GpuCardResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
since = "4.21.0", authorized = {RoleType.Admin})
public class UpdateGpuCardCmd extends BaseCmd {
/// //////////////////////////////////////////////////
/// ///////////// API parameters /////////////////////
/// //////////////////////////////////////////////////
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = GpuCardResponse.class, required = true,
description = "the ID of the GPU card")
private Long id;
@Parameter(name = ApiConstants.DEVICE_NAME, type = CommandType.STRING,
description = "the device name of the GPU card")
private String deviceName;
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "the display name of the GPU card")
private String name;
@Parameter(name = ApiConstants.VENDOR_NAME, type = CommandType.STRING,
description = "the vendor name of the GPU card")
private String vendorName;
/// //////////////////////////////////////////////////
/// //////////////// Accessors ///////////////////////
/// //////////////////////////////////////////////////
public Long getId() {
return id;
}
public String getDeviceName() {
return deviceName;
}
public String getName() {
return name;
}
public String getVendorName() {
return vendorName;
}
@Override
public void execute() {
try {
GpuCard gpuCard = gpuService.updateGpuCard(this);
if (gpuCard != null) {
GpuCardResponse response = new GpuCardResponse(gpuCard);
response.setResponseName(getCommandName());
setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update GPU card");
}
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update GPU card: " + e.getMessage());
}
}
/// //////////////////////////////////////////////////
/// //////////// API Implementation///////////////////
/// //////////////////////////////////////////////////
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,109 @@
// 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.GpuCardResponse;
import org.apache.cloudstack.api.response.GpuDeviceResponse;
import org.apache.cloudstack.api.response.VgpuProfileResponse;
import org.apache.cloudstack.gpu.GpuDevice;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils;
@APICommand(name = "updateGpuDevice", description = "Updates an existing GPU device",
responseObject = GpuDeviceResponse.class, since = "4.21.0", requestHasSensitiveInfo = false,
responseHasSensitiveInfo = false, authorized = {RoleType.Admin})
public class UpdateGpuDeviceCmd extends BaseCmd {
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = GpuDeviceResponse.class, required = true,
description = "ID of the GPU device to update")
private Long id;
@Parameter(name = ApiConstants.GPU_CARD_ID, type = CommandType.UUID, entityType = GpuCardResponse.class,
description = "New GPU card ID")
private Long gpuCardId;
@Parameter(name = ApiConstants.VGPU_PROFILE_ID, type = CommandType.UUID, entityType = VgpuProfileResponse.class,
description = "New vGPU profile ID")
private Long vgpuProfileId;
@Parameter(name = "type", type = CommandType.STRING, description = "New type of GPU device (PCI, MDEV, VGPUOnly)")
private String type;
@Parameter(name = "parentgpudeviceid", type = CommandType.UUID, entityType = GpuDeviceResponse.class,
description = "New parent GPU device ID (for virtual GPU devices)")
private Long parentGpuDeviceId;
@Parameter(name = ApiConstants.NUMA_NODE, type = CommandType.STRING,
description = "New NUMA node of the GPU device")
private String numaNode;
public Long getId() {
return id;
}
public Long getGpuCardId() {
return gpuCardId;
}
public Long getVgpuProfileId() {
return vgpuProfileId;
}
public GpuDevice.DeviceType getType() {
GpuDevice.DeviceType deviceType = null;
if (StringUtils.isNotBlank(type)) {
deviceType = EnumUtils.getEnumIgnoreCase(GpuDevice.DeviceType.class, type);
if (deviceType == null) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid GPU device type: " + type);
}
}
return deviceType;
}
public Long getParentGpuDeviceId() {
return parentGpuDeviceId;
}
public String getNumaNode() {
return numaNode;
}
@Override
public void execute() {
try {
GpuDeviceResponse response = gpuService.updateGpuDevice(this);
response.setResponseName(getCommandName());
setResponseObject(response);
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,129 @@
// 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.VgpuProfileResponse;
@APICommand(name = "updateVgpuProfile", description = "Updates a vGPU profile in the system",
responseObject = VgpuProfileResponse.class, requestHasSensitiveInfo = false,
responseHasSensitiveInfo = false, since = "4.21.0", authorized = {RoleType.Admin})
public class UpdateVgpuProfileCmd extends BaseCmd {
/// //////////////////////////////////////////////////
/// ///////////// API parameters /////////////////////
/// //////////////////////////////////////////////////
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = VgpuProfileResponse.class, required = true,
description = "the ID of the vGPU profile")
private Long id;
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "the name of the vGPU profile")
private String profileName;
@Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING,
description = "the description of the vGPU profile")
private String description;
@Parameter(name = ApiConstants.MAX_VGPU_PER_PHYSICAL_GPU, type = CommandType.LONG,
description = "the maximum number of vGPUs per physical GPU")
private Long maxVgpuPerPgpu;
@Parameter(name = ApiConstants.VIDEORAM, type = CommandType.LONG,
description = "the video RAM size in MB")
private Long videoRam;
@Parameter(name = ApiConstants.MAXHEADS, type = CommandType.LONG,
description = "the maximum number of display heads")
private Long maxHeads;
@Parameter(name = ApiConstants.MAXRESOLUTIONX, type = CommandType.LONG,
description = "the maximum X resolution")
private Long maxResolutionX;
@Parameter(name = ApiConstants.MAXRESOLUTIONY, type = CommandType.LONG,
description = "the maximum Y resolution")
private Long maxResolutionY;
/// //////////////////////////////////////////////////
/// //////////////// Accessors ///////////////////////
/// //////////////////////////////////////////////////
public Long getId() {
return id;
}
public String getProfileName() {
return profileName;
}
public String getDescription() {
return description;
}
public Long getMaxVgpuPerPgpu() {
return maxVgpuPerPgpu;
}
public Long getVideoRam() {
return videoRam;
}
public Long getMaxHeads() {
return maxHeads;
}
public Long getMaxResolutionX() {
return maxResolutionX;
}
public Long getMaxResolutionY() {
return maxResolutionY;
}
@Override
public void execute() {
try {
VgpuProfileResponse response = gpuService.updateVgpuProfile(this);
if (response != null) {
setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update vGPU profile");
}
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR,
"Failed to update vGPU profile: " + e.getMessage());
}
}
/// //////////////////////////////////////////////////
/// //////////// API Implementation///////////////////
/// //////////////////////////////////////////////////
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -32,6 +32,7 @@ import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.DiskOfferingResponse;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
import org.apache.cloudstack.api.response.VgpuProfileResponse;
import org.apache.cloudstack.api.response.VsphereStoragePoliciesResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.vm.lease.VMLeaseManager;
@ -263,6 +264,25 @@ public class CreateServiceOfferingCmd extends BaseCmd {
description = "Lease expiry action, valid values are STOP and DESTROY")
private String leaseExpiryAction;
@Parameter(name = ApiConstants.VGPU_PROFILE_ID,
type = CommandType.UUID,
entityType = VgpuProfileResponse.class,
description = "the ID of the vGPU profile to which service offering should be mapped",
since = "4.21")
private Long vgpuProfileId;
@Parameter(name = ApiConstants.GPU_COUNT,
type = CommandType.INTEGER,
description = "Count of GPUs to be used with this service offering. This is applicable only when passed with vGPU profile.",
since = "4.21")
private Integer gpuCount;
@Parameter(name = ApiConstants.GPU_DISPLAY,
type = CommandType.BOOLEAN,
description = "Whether to enable GPU display for this service offering. This is applicable only when passed with vGPU profile. Defaults to false.",
since = "4.21")
private Boolean gpuDisplay;
@Parameter(name = ApiConstants.EXTERNAL_DETAILS,
type = CommandType.MAP,
description = "Details in key/value pairs using format externaldetails[i].keyname=keyvalue. Example: externaldetails[0].endpoint.url=urlvalue",
@ -529,6 +549,18 @@ public class CreateServiceOfferingCmd extends BaseCmd {
return Boolean.TRUE.equals(purgeResources);
}
public Long getVgpuProfileId() {
return vgpuProfileId;
}
public Integer getGpuCount() {
return gpuCount;
}
public Boolean getGpuDisplay() {
return Boolean.TRUE.equals(gpuDisplay);
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -0,0 +1,96 @@
// 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.api.command.user.gpu;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.GpuCardResponse;
import org.apache.cloudstack.api.response.ListResponse;
@APICommand(name = "listGpuCards", description = "Lists all available GPU cards",
responseObject = GpuCardResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
since = "4.21.0")
public class ListGpuCardsCmd extends BaseListCmd {
/// //////////////////////////////////////////////////
/// ///////////// API parameters /////////////////////
/// //////////////////////////////////////////////////
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = GpuCardResponse.class,
description = "ID of the GPU card")
private Long id;
@Parameter(name = ApiConstants.VENDOR_NAME, type = CommandType.STRING,
description = "vendor name of the GPU card")
private String vendorName;
@Parameter(name = ApiConstants.VENDOR_ID, type = CommandType.STRING,
description = "vendor ID of the GPU card")
private String vendorId;
@Parameter(name = ApiConstants.DEVICE_ID, type = CommandType.STRING,
description = "device ID of the GPU card")
private String deviceId;
@Parameter(name = ApiConstants.DEVICE_NAME, type = CommandType.STRING,
description = "device name of the GPU card")
private String deviceName;
@Parameter(name = ApiConstants.ACTIVE_ONLY, type = CommandType.BOOLEAN,
description = "If true, only GPU cards which have a device will be listed. If false, all GPU cards will be listed.")
private Boolean activeOnly;
/// //////////////////////////////////////////////////
/// //////////////// Accessors ///////////////////////
/// //////////////////////////////////////////////////
public Long getId() {
return id;
}
public String getVendorName() {
return vendorName;
}
public String getVendorId() {
return vendorId;
}
public String getDeviceId() {
return deviceId;
}
public String getDeviceName() {
return deviceName;
}
public boolean getActiveOnly() {
return Boolean.TRUE.equals(activeOnly);
}
/// //////////////////////////////////////////////////
/// //////////// API Implementation///////////////////
/// //////////////////////////////////////////////////
@Override public void execute() {
ListResponse<GpuCardResponse> response = gpuService.listGpuCards(this);
response.setResponseName(getCommandName());
setResponseObject(response);
}
}

View File

@ -0,0 +1,65 @@
// 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.api.command.user.gpu;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ResponseObject;
import org.apache.cloudstack.api.command.user.UserCmd;
import org.apache.cloudstack.api.response.GpuDeviceResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.context.CallContext;
@APICommand(name = "listGpuDevices", description = "Lists all available GPU devices",
responseView = ResponseObject.ResponseView.Restricted,
responseObject = GpuDeviceResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
since = "4.21.0", authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class ListGpuDevicesCmd extends BaseListCmd implements UserCmd {
/// //////////////////////////////////////////////////
/// ///////////// API parameters /////////////////////
/// //////////////////////////////////////////////////
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, type = CommandType.UUID, entityType = UserVmResponse.class,
description = "the virtual machine ID to which the GPU device is allocated")
private Long vmId;
/// //////////////////////////////////////////////////
/// //////////////// Accessors ///////////////////////
/// //////////////////////////////////////////////////
public Long getVmId() {
return vmId;
}
/// //////////////////////////////////////////////////
/// //////////// API Implementation //////////////////
/// //////////////////////////////////////////////////
@Override
public void execute() {
CallContext.current().setEventDetails("Listing GPU devices");
ListResponse<GpuDeviceResponse> response = gpuService.listGpuDevices(this);
response.setResponseName(getCommandName());
setResponseObject(response);
}
}

View File

@ -0,0 +1,80 @@
// 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.api.command.user.gpu;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.GpuCardResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.VgpuProfileResponse;
@APICommand(name = "listVgpuProfiles", description = "Lists all available vGPU profiles",
responseObject = VgpuProfileResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
since = "4.21.0")
public class ListVgpuProfilesCmd extends BaseListCmd {
/// //////////////////////////////////////////////////
/// ///////////// API parameters /////////////////////
/// //////////////////////////////////////////////////
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = VgpuProfileResponse.class,
description = "ID of the vGPU profile")
private Long id;
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "name of the vGPU profile")
private String name;
@Parameter(name = ApiConstants.GPU_CARD_ID, type = CommandType.UUID, entityType = GpuCardResponse.class,
description = "the GPU card ID associated with this GPU device")
private Long cardId;
@Parameter(name = ApiConstants.ACTIVE_ONLY, type = CommandType.BOOLEAN,
description = "If true, only vGPU profiles which have a device will be listed. If false, all vGPU profiles will be listed.")
private Boolean activeOnly;
/// //////////////////////////////////////////////////
/// //////////////// Accessors ///////////////////////
/// //////////////////////////////////////////////////
public Long getId() {
return id;
}
public String getName() {
return name;
}
public Long getCardId() {
return cardId;
}
public boolean getActiveOnly() {
return Boolean.TRUE.equals(activeOnly);
}
/// //////////////////////////////////////////////////
/// //////////// API Implementation///////////////////
/// //////////////////////////////////////////////////
@Override public void execute() {
ListResponse<VgpuProfileResponse> response = gpuService.listVgpuProfiles(this);
response.setResponseName(getCommandName());
setResponseObject(response);
}
}

View File

@ -26,6 +26,7 @@ import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
import org.apache.cloudstack.api.response.TemplateResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.VgpuProfileResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils;
@ -110,6 +111,19 @@ public class ListServiceOfferingsCmd extends BaseListProjectAndAccountResourcesC
since = "4.20.0")
private Long templateId;
@Parameter(name = ApiConstants.VGPU_PROFILE_ID,
type = CommandType.UUID,
entityType = VgpuProfileResponse.class,
description = "The ID of the vGPU profile that listed offerings must support",
since = "4.21.0")
private Long vgpuProfileId;
@Parameter(name = ApiConstants.GPU_ENABLED,
type = CommandType.BOOLEAN,
description = "Flag to indicate if the service offering supports GPU. If set to true, only service offerings that support GPU will be returned.",
since = "4.21.0")
private Boolean gpuEnabled;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -171,6 +185,14 @@ public class ListServiceOfferingsCmd extends BaseListProjectAndAccountResourcesC
return templateId;
}
public Long getVgpuProfileId() {
return vgpuProfileId;
}
public Boolean getGpuEnabled() {
return gpuEnabled;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -172,6 +172,12 @@ public class ListVMsCmd extends BaseListRetrieveOnlyResourceCountCmd implements
since = "4.21.0")
private Boolean onlyLeasedInstances = false;
@Parameter(name = ApiConstants.GPU_ENABLED,
type = CommandType.BOOLEAN,
description = "Flag to indicate if the VMs should be filtered by GPU support. If set to true, only VMs that support GPU will be returned.",
since = "4.21.0")
private Boolean gpuEnabled;
@Parameter(name = ApiConstants.EXTENSION_ID, type = CommandType.UUID,
entityType = ExtensionResponse.class, description = "The ID of the Orchestrator extension for the VM",
since = "4.21.0")
@ -324,6 +330,10 @@ public class ListVMsCmd extends BaseListRetrieveOnlyResourceCountCmd implements
return BooleanUtils.toBoolean(onlyLeasedInstances);
}
public Boolean getGpuEnabled() {
return gpuEnabled;
}
public Long getExtensionId() {
return extensionId;
}

View File

@ -231,6 +231,18 @@ public class AccountResponse extends BaseResponse implements ResourceLimitAndCou
@Param(description = "the total memory (in MB) available to be created for this account", since = "4.2.0")
private String memoryAvailable;
@SerializedName("gpulimit")
@Param(description = "the total number of gpus the account can own", since = "4.21.0")
private String gpuLimit;
@SerializedName("gputotal")
@Param(description = "the total number of gpus owned by account", since = "4.21.0")
private Long gpuTotal;
@SerializedName("gpuavailable")
@Param(description = "the total number of gpus available to be created for this account", since = "4.21.0")
private String gpuAvailable;
@SerializedName("primarystoragelimit")
@Param(description = "the total primary storage space (in GiB) the account can own", since = "4.2.0")
private String primaryStorageLimit;
@ -489,6 +501,21 @@ public class AccountResponse extends BaseResponse implements ResourceLimitAndCou
this.vmRunning = vmRunning;
}
@Override
public void setGpuLimit(String gpuLimit) {
this.gpuLimit = gpuLimit;
}
@Override
public void setGpuTotal(Long gpuTotal) {
this.gpuTotal = gpuTotal;
}
@Override
public void setGpuAvailable(String gpuAvailable) {
this.gpuAvailable = gpuAvailable;
}
public void setState(String state) {
this.state = state;
}

View File

@ -183,6 +183,15 @@ public class DomainResponse extends BaseResponseWithAnnotations implements Resou
@SerializedName("memoryavailable") @Param(description="the total memory (in MB) available to be created for this domain", since="4.2.0")
private String memoryAvailable;
@SerializedName("gpulimit") @Param(description="the total number of gpus the domain can own", since="4.21.0")
private String gpuLimit;
@SerializedName("gputotal") @Param(description="the total number of gpus owned by domain", since="4.21.0")
private Long gpuTotal;
@SerializedName("gpuavailable") @Param(description="the total number of gpus available to be created for this domain", since="4.21.0")
private String gpuAvailable;
@SerializedName("primarystoragelimit") @Param(description="the total primary storage space (in GiB) the domain can own", since="4.2.0")
private String primaryStorageLimit;
@ -478,6 +487,21 @@ public class DomainResponse extends BaseResponseWithAnnotations implements Resou
this.memoryAvailable = memoryAvailable;
}
@Override
public void setGpuLimit(String gpuLimit) {
this.gpuLimit = gpuLimit;
}
@Override
public void setGpuTotal(Long gpuTotal) {
this.gpuTotal = gpuTotal;
}
@Override
public void setGpuAvailable(String gpuAvailable) {
this.gpuAvailable = gpuAvailable;
}
@Override
public void setPrimaryStorageLimit(String primaryStorageLimit) {
this.primaryStorageLimit = primaryStorageLimit;

View File

@ -0,0 +1,109 @@
// 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.api.response;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.EntityReference;
import org.apache.cloudstack.gpu.GpuCard;
@EntityReference(value = GpuCard.class)
public class GpuCardResponse extends BaseResponse {
@SerializedName(ApiConstants.ID)
@Param(description = "the ID of the GPU card")
protected String id;
@SerializedName("deviceid")
@Param(description = "the device ID of the GPU card")
protected String deviceId;
@SerializedName("devicename")
@Param(description = "the device name of the GPU card")
protected String deviceName;
@SerializedName("name")
@Param(description = "the display name of the GPU card")
protected String name;
@SerializedName("vendorname")
@Param(description = "the vendor name of the GPU card")
protected String vendorName;
@SerializedName("vendorid")
@Param(description = "the vendor ID of the GPU card")
protected String vendorId;
public GpuCardResponse(GpuCard gpuCard) {
super("gpucard");
id = gpuCard.getUuid();
deviceId = gpuCard.getDeviceId();
deviceName = gpuCard.getDeviceName();
name = gpuCard.getName();
vendorName = gpuCard.getVendorName();
vendorId = gpuCard.getVendorId();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getDeviceName() {
return deviceName;
}
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getVendorName() {
return vendorName;
}
public void setVendorName(String vendorName) {
this.vendorName = vendorName;
}
public String getVendorId() {
return vendorId;
}
public void setVendorId(String vendorId) {
this.vendorId = vendorId;
}
}

View File

@ -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.
package org.apache.cloudstack.api.response;
import com.cloud.serializer.Param;
import com.cloud.vm.VirtualMachine;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.EntityReference;
import org.apache.cloudstack.gpu.GpuDevice;
@EntityReference(value = GpuDevice.class)
public class GpuDeviceResponse extends BaseResponse {
@SerializedName(ApiConstants.ID)
@Param(description = "the ID of the GPU device")
private String id;
@SerializedName(ApiConstants.BUS_ADDRESS)
@Param(description = "bus address of the GPU device or MDEV UUID for vGPU devices")
private String bussAddress;
@SerializedName(ApiConstants.GPU_DEVICE_TYPE)
@Param(description = "bus address of the GPU device")
private GpuDevice.DeviceType type;
@SerializedName(ApiConstants.HOST_ID)
@Param(description = "the host ID where the GPU device is attached")
private String hostId;
@SerializedName(ApiConstants.HOST_NAME)
@Param(description = "the host name where the GPU device is attached")
private String hostName;
@SerializedName(ApiConstants.GPU_CARD_ID)
@Param(description = "the GPU card ID associated with this GPU device")
private String gpuCardId;
@SerializedName(ApiConstants.GPU_CARD_NAME)
@Param(description = "the GPU card name associated with this GPU device")
private String gpuCardName;
@SerializedName(ApiConstants.VGPU_PROFILE_ID)
@Param(description = "the vGPU profile ID assigned to this GPU device")
private String vgpuProfileId;
@SerializedName(ApiConstants.VGPU_PROFILE_NAME)
@Param(description = "the vGPU profile name assigned to this GPU device")
private String vgpuProfileName;
@SerializedName(ApiConstants.VIRTUAL_MACHINE_ID)
@Param(description = "the vGPU profile ID assigned to this GPU device")
private String vmId;
@SerializedName(ApiConstants.VIRTUAL_MACHINE_NAME)
@Param(description = "the vGPU profile name assigned to this GPU device")
private String vmName;
@SerializedName(ApiConstants.VIRTUAL_MACHINE_STATE)
@Param(description = "the state of the virtual machine to which this GPU device is allocated")
private VirtualMachine.State vmState;
@SerializedName(ApiConstants.STATE)
@Param(description = "the vGPU profile name assigned to this GPU device")
private GpuDevice.State state;
@SerializedName(ApiConstants.MANAGED_STATE)
@Param(description = "the managed state of the GPU device (Enabled/Disabled)")
private GpuDevice.ManagedState managedState;
@SerializedName(ApiConstants.PARENT_GPU_DEVICE_ID)
@Param(description = "the ID of the parent GPU device, if this is a vGPU")
private String parentGpuDeviceId;
@SerializedName(ApiConstants.NUMA_NODE)
@Param(description = "the NUMA node where the GPU device is located")
private String numaNode;
public GpuDeviceResponse() {
// Empty constructor for serialization
super("gpudevice");
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getBussAddress() {
return bussAddress;
}
public void setBussAddress(String bussAddress) {
this.bussAddress = bussAddress;
}
public GpuDevice.DeviceType getType() {
return type;
}
public void setType(GpuDevice.DeviceType type) {
this.type = type;
}
public String getHostId() {
return hostId;
}
public void setHostId(String hostId) {
this.hostId = hostId;
}
public String getHostName() {
return hostName;
}
public void setHostName(String hostName) {
this.hostName = hostName;
}
public String getGpuCardId() {
return gpuCardId;
}
public void setGpuCardId(String gpuCardId) {
this.gpuCardId = gpuCardId;
}
public String getGpuCardName() {
return gpuCardName;
}
public void setGpuCardName(String gpuCardName) {
this.gpuCardName = gpuCardName;
}
public String getVgpuProfileId() {
return vgpuProfileId;
}
public void setVgpuProfileId(String vgpuProfileId) {
this.vgpuProfileId = vgpuProfileId;
}
public String getVgpuProfileName() {
return vgpuProfileName;
}
public void setVgpuProfileName(String vgpuProfileName) {
this.vgpuProfileName = vgpuProfileName;
}
public String getVmId() {
return vmId;
}
public void setVmId(String vmId) {
this.vmId = vmId;
}
public String getVmName() {
return vmName;
}
public void setVmName(String vmName) {
this.vmName = vmName;
}
public VirtualMachine.State getVmState() {
return vmState;
}
public void setVmState(VirtualMachine.State vmState) {
this.vmState = vmState;
}
public GpuDevice.State getState() {
return state;
}
public void setState(GpuDevice.State state) {
this.state = state;
}
public GpuDevice.ManagedState getManagedState() {
return managedState;
}
public void setManagedState(GpuDevice.ManagedState managedState) {
this.managedState = managedState;
}
public String getParentGpuDeviceId() {
return parentGpuDeviceId;
}
public void setParentGpuDeviceId(String parentGpuDeviceId) {
this.parentGpuDeviceId = parentGpuDeviceId;
}
public String getNumaNode() {
return numaNode;
}
public void setNumaNode(String numaNode) {
this.numaNode = numaNode;
}
}

View File

@ -165,6 +165,14 @@ public class HostResponse extends BaseResponseWithAnnotations {
@Param(description = "the amount of the host's memory currently used")
private Long memoryUsed;
@SerializedName("gputotal")
@Param(description = "Total GPUs on the Host", responseObject = Long.class, since = "4.21")
private Long gpuTotal;
@SerializedName("gpuused")
@Param(description = "Used GPUs on the Host", responseObject = Long.class, since = "4.21")
private Long gpuUsed;
@SerializedName(ApiConstants.GPUGROUP)
@Param(description = "GPU cards present in the host", responseObject = GpuResponse.class, since = "4.4")
private List<GpuResponse> gpuGroup;
@ -448,6 +456,14 @@ public class HostResponse extends BaseResponseWithAnnotations {
this.memoryUsed = memoryUsed;
}
public void setGpuTotal(Long gpuTotal) {
this.gpuTotal = gpuTotal;
}
public void setGpuUsed(Long gpuUsed) {
this.gpuUsed = gpuUsed;
}
public void setGpuGroup(List<GpuResponse> gpuGroup) {
this.gpuGroup = gpuGroup;
}
@ -920,6 +936,14 @@ public class HostResponse extends BaseResponseWithAnnotations {
return memoryAllocatedBytes;
}
public Long getGpuTotal() {
return gpuTotal;
}
public Long getGpuUsed() {
return gpuUsed;
}
public Boolean getTagARule() {
return isTagARule;
}

View File

@ -116,6 +116,18 @@ public class ProjectResponse extends BaseResponse implements ResourceLimitAndCou
@Param(description = "the total memory (in MB) available to be created for this project", since = "4.2.0")
private String memoryAvailable;
@SerializedName("gpulimit")
@Param(description = "the total number of gpus the project can own", since = "4.21.0")
private String gpuLimit;
@SerializedName("gputotal")
@Param(description = "the total number of gpus owned by project", since = "4.21.0")
private Long gpuTotal;
@SerializedName("gpuavailable")
@Param(description = "the total number of gpus available to be created for this project", since = "4.21.0")
private String gpuAvailable;
@SerializedName("primarystoragelimit")
@Param(description = "the total primary storage space (in GiB) the project can own", since = "4.2.0")
private String primaryStorageLimit;
@ -483,6 +495,21 @@ public class ProjectResponse extends BaseResponse implements ResourceLimitAndCou
this.memoryAvailable = memoryAvailable;
}
@Override
public void setGpuLimit(String gpuLimit) {
this.gpuLimit = gpuLimit;
}
@Override
public void setGpuTotal(Long gpuTotal) {
this.gpuTotal = gpuTotal;
}
@Override
public void setGpuAvailable(String gpuAvailable) {
this.gpuAvailable = gpuAvailable;
}
@Override
public void setPrimaryStorageLimit(String primaryStorageLimit) {
this.primaryStorageLimit = primaryStorageLimit;

View File

@ -48,6 +48,12 @@ public interface ResourceLimitAndCountResponse {
public void setMemoryAvailable(String memoryAvailable);
public void setGpuLimit(String gpuLimit);
public void setGpuTotal(Long gpuTotal);
public void setGpuAvailable(String gpuAvailable);
public void setPrimaryStorageLimit(String primaryStorageLimit);
public void setPrimaryStorageTotal(Long primaryStorageTotal);

View File

@ -234,6 +234,46 @@ public class ServiceOfferingResponse extends BaseResponseWithAnnotations {
@Param(description = "true if virtual machine root disk will be encrypted on storage", since = "4.18")
private Boolean encryptRoot;
@SerializedName(ApiConstants.GPU_CARD_ID)
@Param(description = "the ID of the gpu card to which service offering is linked", since = "4.21")
private String gpuCardId;
@SerializedName(ApiConstants.GPU_CARD_NAME)
@Param(description = "the name of the gpu card to which service offering is linked", since = "4.21")
private String gpuCardName;
@SerializedName(ApiConstants.VGPU_PROFILE_ID)
@Param(description = "the ID of the vgpu profile to which service offering is linked", since = "4.21")
private String vgpuProfileId;
@SerializedName(ApiConstants.VGPU_PROFILE_NAME)
@Param(description = "the name of the vgpu profile to which service offering is linked", since = "4.21")
private String vgpuProfileName;
@SerializedName(ApiConstants.VIDEORAM)
@Param(description = "the video RAM size in MB")
private Long videoRam;
@SerializedName(ApiConstants.MAXHEADS)
@Param(description = "the maximum number of display heads")
private Long maxHeads;
@SerializedName(ApiConstants.MAXRESOLUTIONX)
@Param(description = "the maximum X resolution")
private Long maxResolutionX;
@SerializedName(ApiConstants.MAXRESOLUTIONY)
@Param(description = "the maximum Y resolution")
private Long maxResolutionY;
@SerializedName(ApiConstants.GPU_COUNT)
@Param(description = "the count of GPUs to attach ", since = "4.21")
private Integer gpuCount;
@SerializedName(ApiConstants.GPU_DISPLAY)
@Param(description = "whether GPU device is used for display or not ", since = "4.21")
private Boolean gpuDisplay;
@SerializedName(ApiConstants.PURGE_RESOURCES)
@Param(description = "Whether to cleanup VM and its associated resource upon expunge", since = "4.20")
private Boolean purgeResources;
@ -584,6 +624,86 @@ public class ServiceOfferingResponse extends BaseResponseWithAnnotations {
public void setEncryptRoot(Boolean encrypt) { this.encryptRoot = encrypt; }
public String getVgpuProfileName() {
return vgpuProfileName;
}
public void setVgpuProfileName(String vgpuProfileName) {
this.vgpuProfileName = vgpuProfileName;
}
public Long getVideoRam() {
return videoRam;
}
public void setVideoRam(Long videoRam) {
this.videoRam = videoRam;
}
public Long getMaxHeads() {
return maxHeads;
}
public void setMaxHeads(Long maxHeads) {
this.maxHeads = maxHeads;
}
public Long getMaxResolutionX() {
return maxResolutionX;
}
public void setMaxResolutionX(Long maxResolutionX) {
this.maxResolutionX = maxResolutionX;
}
public Long getMaxResolutionY() {
return maxResolutionY;
}
public void setMaxResolutionY(Long maxResolutionY) {
this.maxResolutionY = maxResolutionY;
}
public String getVgpuProfileId() {
return vgpuProfileId;
}
public void setVgpuProfileId(String vgpuProfileId) {
this.vgpuProfileId = vgpuProfileId;
}
public String getGpuCardName() {
return gpuCardName;
}
public void setGpuCardName(String gpuCardName) {
this.gpuCardName = gpuCardName;
}
public String getGpuCardId() {
return gpuCardId;
}
public void setGpuCardId(String gpuCardId) {
this.gpuCardId = gpuCardId;
}
public Integer getGpuCount() {
return gpuCount;
}
public void setGpuCount(Integer gpuCount) {
this.gpuCount = gpuCount;
}
public Boolean getGpuDisplay() {
return gpuDisplay;
}
public void setGpuDisplay(Boolean gpuDisplay) {
this.gpuDisplay = gpuDisplay;
}
public void setPurgeResources(Boolean purgeResources) {
this.purgeResources = purgeResources;
}

View File

@ -182,6 +182,42 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
@Param(description = "the name of the disk offering of the virtual machine. This parameter should not be used for retrieving disk offering details of DATA volumes. Use listVolumes API instead", since = "4.4")
private String diskOfferingName;
@SerializedName(ApiConstants.GPU_CARD_ID)
@Param(description = "the ID of the gpu card to which service offering is linked", since = "4.21")
private String gpuCardId;
@SerializedName(ApiConstants.GPU_CARD_NAME)
@Param(description = "the name of the gpu card to which service offering is linked", since = "4.21")
private String gpuCardName;
@SerializedName(ApiConstants.VGPU_PROFILE_ID)
@Param(description = "the ID of the vgpu profile to which service offering is linked", since = "4.21")
private String vgpuProfileId;
@SerializedName(ApiConstants.VGPU_PROFILE_NAME)
@Param(description = "the name of the vgpu profile to which service offering is linked", since = "4.21")
private String vgpuProfileName;
@SerializedName(ApiConstants.VIDEORAM)
@Param(description = "the video RAM size in MB")
private Long videoRam;
@SerializedName(ApiConstants.MAXHEADS)
@Param(description = "the maximum number of display heads")
private Long maxHeads;
@SerializedName(ApiConstants.MAXRESOLUTIONX)
@Param(description = "the maximum X resolution")
private Long maxResolutionX;
@SerializedName(ApiConstants.MAXRESOLUTIONY)
@Param(description = "the maximum Y resolution")
private Long maxResolutionY;
@SerializedName(ApiConstants.GPU_COUNT)
@Param(description = "the count of GPUs on the virtual machine", since = "4.21")
private Integer gpuCount;
@SerializedName(ApiConstants.BACKUP_OFFERING_ID)
@Param(description = "the ID of the backup offering of the virtual machine", since = "4.14")
private String backupOfferingId;
@ -565,6 +601,42 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
return diskOfferingName;
}
public String getGpuCardId() {
return gpuCardId;
}
public String getGpuCardName() {
return gpuCardName;
}
public String getVgpuProfileId() {
return vgpuProfileId;
}
public String getVgpuProfileName() {
return vgpuProfileName;
}
public Long getVideoRam() {
return videoRam;
}
public Long getMaxHeads() {
return maxHeads;
}
public Long getMaxResolutionX() {
return maxResolutionX;
}
public Long getMaxResolutionY() {
return maxResolutionY;
}
public Integer getGpuCount() {
return gpuCount;
}
public String getBackupOfferingId() {
return backupOfferingId;
}
@ -847,6 +919,42 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
this.diskOfferingName = diskOfferingName;
}
public void setGpuCardId(String gpuCardId) {
this.gpuCardId = gpuCardId;
}
public void setGpuCardName(String gpuCardName) {
this.gpuCardName = gpuCardName;
}
public void setVgpuProfileId(String vgpuProfileId) {
this.vgpuProfileId = vgpuProfileId;
}
public void setVgpuProfileName(String vgpuProfileName) {
this.vgpuProfileName = vgpuProfileName;
}
public void setVideoRam(Long videoRam) {
this.videoRam = videoRam;
}
public void setMaxHeads(Long maxHeads) {
this.maxHeads = maxHeads;
}
public void setMaxResolutionX(Long maxResolutionX) {
this.maxResolutionX = maxResolutionX;
}
public void setMaxResolutionY(Long maxResolutionY) {
this.maxResolutionY = maxResolutionY;
}
public void setGpuCount(Integer gpuCount) {
this.gpuCount = gpuCount;
}
public void setBackupOfferingId(String backupOfferingId) {
this.backupOfferingId = backupOfferingId;
}

View File

@ -0,0 +1,135 @@
// 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.api.response;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.EntityReference;
import org.apache.cloudstack.gpu.GpuCard;
import org.apache.cloudstack.gpu.VgpuProfile;
@EntityReference(value = VgpuProfile.class)
public class VgpuProfileResponse extends GpuCardResponse {
@SerializedName(ApiConstants.DESCRIPTION)
@Param(description = "the description of the vGPU profile")
private String description;
@SerializedName(ApiConstants.GPU_CARD_ID)
@Param(description = "the ID of the GPU card associated with this vGPU profile")
private String gpuCardId;
@SerializedName(ApiConstants.GPU_CARD_NAME)
@Param(description = "the name of the vGPU profile")
private String gpuCardName;
@SerializedName(ApiConstants.MAX_VGPU_PER_PHYSICAL_GPU)
@Param(description = "the maximum number of vGPUs per physical GPU")
private Long maxVgpuPerPgpu;
@SerializedName(ApiConstants.VIDEORAM)
@Param(description = "the video RAM size in MB")
private Long videoRam;
@SerializedName(ApiConstants.MAXHEADS)
@Param(description = "the maximum number of display heads")
private Long maxHeads;
@SerializedName(ApiConstants.MAXRESOLUTIONX)
@Param(description = "the maximum X resolution")
private Long maxResolutionX;
@SerializedName(ApiConstants.MAXRESOLUTIONY)
@Param(description = "the maximum Y resolution")
private Long maxResolutionY;
public VgpuProfileResponse(VgpuProfile vgpuProfile, GpuCard gpuCard) {
super(gpuCard);
id = vgpuProfile.getUuid();
name = vgpuProfile.getName();
description = vgpuProfile.getDescription();
gpuCardId = gpuCard.getUuid();
gpuCardName = gpuCard.getName();
maxVgpuPerPgpu = vgpuProfile.getMaxVgpuPerPgpu();
videoRam = vgpuProfile.getVideoRam();
maxHeads = vgpuProfile.getMaxHeads();
maxResolutionX = vgpuProfile.getMaxResolutionX();
maxResolutionY = vgpuProfile.getMaxResolutionY();
setObjectName("vgpuprofile");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public String getGpuCardId() {
return gpuCardId;
}
public String getGpuCardName() {
return gpuCardName;
}
public Long getMaxVgpuPerPgpu() {
return maxVgpuPerPgpu;
}
public void setDescription(String description) {
this.description = description;
}
public Long getVideoRam() {
return videoRam;
}
public void setVideoRam(Long videoRam) {
this.videoRam = videoRam;
}
public Long getMaxHeads() {
return maxHeads;
}
public void setMaxHeads(Long maxHeads) {
this.maxHeads = maxHeads;
}
public Long getMaxResolutionX() {
return maxResolutionX;
}
public void setMaxResolutionX(Long maxResolutionX) {
this.maxResolutionX = maxResolutionX;
}
public Long getMaxResolutionY() {
return maxResolutionY;
}
public void setMaxResolutionY(Long maxResolutionY) {
this.maxResolutionY = maxResolutionY;
}
}

View File

@ -97,6 +97,14 @@ public class ZoneResponse extends BaseResponseWithAnnotations implements SetReso
@Param(description = "true if security groups support is enabled, false otherwise")
private Boolean securityGroupsEnabled;
@SerializedName("gputotal")
@Param(description = "Total GPUs in the Zone", responseObject = Long.class, since = "4.21")
private Long gpuTotal;
@SerializedName("gpuused")
@Param(description = "Used GPUs in the Zone", responseObject = Long.class, since = "4.21")
private Long gpuUsed;
@SerializedName("allocationstate")
@Param(description = "the allocation state of the cluster")
private String allocationState;
@ -231,6 +239,14 @@ public class ZoneResponse extends BaseResponseWithAnnotations implements SetReso
this.securityGroupsEnabled = securityGroupsEnabled;
}
public void setGpuTotal(Long gpuTotal) {
this.gpuTotal = gpuTotal;
}
public void setGpuUsed(Long gpuUsed) {
this.gpuUsed = gpuUsed;
}
public void setAllocationState(String allocationState) {
this.allocationState = allocationState;
}
@ -366,6 +382,14 @@ public class ZoneResponse extends BaseResponseWithAnnotations implements SetReso
return securityGroupsEnabled;
}
public Long getGpuUsed() {
return gpuUsed;
}
public Long getGpuTotal() {
return gpuTotal;
}
public boolean isLocalStorageEnabled() {
return localStorageEnabled;
}

View File

@ -0,0 +1,69 @@
// 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.gpu;
import org.apache.cloudstack.api.Identity;
import org.apache.cloudstack.api.InternalIdentity;
import java.util.Date;
/**
* GPU card interface representing a physical GPU card model
*/
public interface GpuCard extends InternalIdentity, Identity {
/**
* @return the UUID of the GPU card
*/
String getUuid();
/**
* @return the device ID of the GPU card
*/
String getDeviceId();
/**
* @return the device name of the GPU card
*/
String getDeviceName();
/**
* @return the name of the GPU card
*/
String getName();
/**
* @return the vendor name of the GPU card
*/
String getVendorName();
/**
* @return the vendor ID of the GPU card
*/
String getVendorId();
/**
* @return the date when the GPU card was created
*/
Date getCreated();
/**
* @return the group name of the GPU card based on how the XenServer expects it.
*/
String getGroupName();
}

View File

@ -0,0 +1,42 @@
// 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.gpu;
import org.apache.cloudstack.api.Identity;
import org.apache.cloudstack.api.InternalIdentity;
/**
* GPU device interface representing a physical GPU device
*/
public interface GpuDevice extends InternalIdentity, Identity {
enum State {
Allocated, Free, Error, PartiallyAllocated,
}
enum ManagedState {
Managed, Unmanaged,
}
enum DeviceType {
PCI, MDEV, VGPUOnly,
}
long getHostId();
State getState();
}

View File

@ -0,0 +1,157 @@
// 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.gpu;
import com.cloud.agent.api.VgpuTypesInfo;
import com.cloud.agent.api.to.GPUDeviceTO;
import com.cloud.host.Host;
import com.cloud.utils.component.Manager;
import com.cloud.vm.VirtualMachine;
import org.apache.cloudstack.api.command.admin.gpu.CreateGpuCardCmd;
import org.apache.cloudstack.api.command.admin.gpu.CreateGpuDeviceCmd;
import org.apache.cloudstack.api.command.admin.gpu.CreateVgpuProfileCmd;
import org.apache.cloudstack.api.command.admin.gpu.DeleteGpuCardCmd;
import org.apache.cloudstack.api.command.admin.gpu.DeleteGpuDeviceCmd;
import org.apache.cloudstack.api.command.admin.gpu.DeleteVgpuProfileCmd;
import org.apache.cloudstack.api.command.admin.gpu.UnmanageGpuDeviceCmd;
import org.apache.cloudstack.api.command.admin.gpu.DiscoverGpuDevicesCmd;
import org.apache.cloudstack.api.command.admin.gpu.ManageGpuDeviceCmd;
import org.apache.cloudstack.api.command.user.gpu.ListGpuDevicesCmd;
import org.apache.cloudstack.api.command.admin.gpu.UpdateGpuCardCmd;
import org.apache.cloudstack.api.command.admin.gpu.UpdateGpuDeviceCmd;
import org.apache.cloudstack.api.command.admin.gpu.UpdateVgpuProfileCmd;
import org.apache.cloudstack.api.command.user.gpu.ListGpuCardsCmd;
import org.apache.cloudstack.api.command.user.gpu.ListVgpuProfilesCmd;
import org.apache.cloudstack.api.response.GpuCardResponse;
import org.apache.cloudstack.api.response.GpuDeviceResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.VgpuProfileResponse;
import org.apache.cloudstack.framework.config.ConfigKey;
import java.util.HashMap;
import java.util.List;
public interface GpuService extends Manager {
ConfigKey<Boolean> GpuDetachOnStop = new ConfigKey<>(Boolean.class, "gpu.detach.on.stop", "Advanced", "false",
"Whether to detach GPU devices from VM on stop or keep them allocated", true, ConfigKey.Scope.Domain, null);
GpuCard createGpuCard(CreateGpuCardCmd cmd);
GpuCard updateGpuCard(UpdateGpuCardCmd cmd);
boolean deleteGpuCard(DeleteGpuCardCmd cmd);
VgpuProfileResponse createVgpuProfile(CreateVgpuProfileCmd cmd);
VgpuProfileResponse updateVgpuProfile(UpdateVgpuProfileCmd cmd);
boolean deleteVgpuProfile(DeleteVgpuProfileCmd cmd);
ListResponse<GpuCardResponse> listGpuCards(ListGpuCardsCmd cmd);
ListResponse<VgpuProfileResponse> listVgpuProfiles(ListVgpuProfilesCmd cmd);
GpuDeviceResponse createGpuDevice(CreateGpuDeviceCmd cmd);
GpuDeviceResponse updateGpuDevice(UpdateGpuDeviceCmd cmd);
ListResponse<GpuDeviceResponse> listGpuDevices(ListGpuDevicesCmd cmd);
boolean disableGpuDevice(UnmanageGpuDeviceCmd cmd);
boolean enableGpuDevice(ManageGpuDeviceCmd cmd);
/**
* Deallocate GPU devices for a VM on a host.
*
* @param vmId The ID of the VM to deallocate GPU devices for.
*/
void deallocateAllGpuDevicesForVm(long vmId);
/**
* Deallocate GPU devices for a VM on a host.
*
* @param vmId The ID of the VM to deallocate GPU devices for.
*/
void deallocateGpuDevicesForVmOnHost(long vmId, long hostId);
/**
* Deallocate existing GPU devices for a VM on a host and allocate new GPU devices to the VM.
*
* @param vmId The ID of the VM to allocate GPU devices to.
* @param hostId The ID of the host to allocate GPU devices to.
* @param gpuDevices The list of GPU devices to allocate to the VM.
*/
void allocateGpuDevicesToVmOnHost(long vmId, long hostId, List<VgpuTypesInfo> gpuDevices);
/**
* Discover GPU devices on a host by using the getGPUStatistics command and updating the GPU details for the host.
*
* @param cmd The command to discover GPU devices.
* @return The list of GPU devices.
*/
ListResponse<GpuDeviceResponse> discoverGpuDevices(DiscoverGpuDevicesCmd cmd);
/**
* Check if GPU devices are available for a VM on a host by checking the number of available GPU devices for the
* vGPU profile.
*
* @param host The host to check GPU devices for.
* @param vmId The ID of the VM to check GPU devices for.
* @param vgpuProfile The vGPU profile to check GPU devices for.
* @param gpuCount The number of GPU devices to check for.
* @return True if GPU devices are available, false otherwise.
*/
boolean isGPUDeviceAvailable(Host host, Long vmId, VgpuProfile vgpuProfile, int gpuCount);
/**
* Get GPU devices for a VM on a host by checking the number of available GPU devices for the vGPU profile.
* If the VM already has GPU devices assigned, deallocate them and allocate new GPU devices to the VM.
* The new GPU devices are allocated optimally to the VM.
*
* @param vm The VM to get GPU devices for.
* @param vgpuProfile The vGPU profile to get GPU devices for.
* @param gpuCount The number of GPU devices to get.
* @return The GPU devices.
*/
GPUDeviceTO getGPUDevice(VirtualMachine vm, long hostId, VgpuProfile vgpuProfile, int gpuCount);
/**
* Gets the GPU group details from the GPU devices on a host.
* This fetches the GPU devices from the host and prepares the GPU group details for the host.
* The GPU group details are a map of GPU group name (Card's device name) to a map of vGPU profile name to
* VgpuTypesInfo.
* The VgpuTypesInfo contains the information about the GPU device.
*
* @param hostId The host ID to get GPU group details for.
* @return The GPU group details.
*/
HashMap<String, HashMap<String, VgpuTypesInfo>> getGpuGroupDetailsFromGpuDevicesOnHost(long hostId);
/**
* This method is used to add the GPU devices to the host when the host is discovered or when the GPU devices are
* updated.
*
* @param host The host to add the GPU devices to.
* @param newGpuDevicesInfo The list of GPU devices to add to the host.
*/
void addGpuDevicesToHost(Host host, List<VgpuTypesInfo> newGpuDevicesInfo);
boolean deleteGpuDevices(DeleteGpuDeviceCmd deleteGpuDeviceCmd);
}

View File

@ -0,0 +1,74 @@
// 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.gpu;
import org.apache.cloudstack.api.Identity;
import org.apache.cloudstack.api.InternalIdentity;
import java.util.Date;
/**
* vGPU profile interface representing a virtualized GPU profile
*/
public interface VgpuProfile extends InternalIdentity, Identity {
/**
* @return the UUID of the vGPU profile
*/
String getUuid();
/**
* @return the name of the vGPU profile
*/
String getName();
/**
* @return the description of the vGPU profile
*/
String getDescription();
/**
* @return the date when the vGPU profile was created
*/
Date getCreated();
Long getCardId();
/**
* @return the maximum number of vGPUs per physical GPU
*/
Long getMaxVgpuPerPgpu();
/**
* @return the video RAM size in MB
*/
Long getVideoRam();
/**
* @return the maximum number of display heads
*/
Long getMaxHeads();
/**
* @return the maximum X resolution
*/
Long getMaxResolutionX();
/**
* @return the maximum Y resolution
*/
Long getMaxResolutionY();
}

View File

@ -0,0 +1,90 @@
/*
* 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class CreateGpuCardCmdTest {
@Test
public void getDeviceId() {
CreateGpuCardCmd cmd = new CreateGpuCardCmd();
assertNull(cmd.getDeviceId());
String deviceId = "0000:00:1f.6";
ReflectionTestUtils.setField(cmd, "deviceId", deviceId);
assertEquals(deviceId, cmd.getDeviceId());
}
@Test
public void getDeviceName() {
CreateGpuCardCmd cmd = new CreateGpuCardCmd();
assertNull(cmd.getDeviceName());
String deviceName = "NVIDIA GeForce GTX 1080";
ReflectionTestUtils.setField(cmd, "deviceName", deviceName);
assertEquals(deviceName, cmd.getDeviceName());
}
@Test
public void getName() {
CreateGpuCardCmd cmd = new CreateGpuCardCmd();
assertNull(cmd.getName());
String name = "Test GPU Card";
ReflectionTestUtils.setField(cmd, "name", name);
assertEquals(name, cmd.getName());
}
@Test
public void getVendorName() {
CreateGpuCardCmd cmd = new CreateGpuCardCmd();
assertNull(cmd.getVendorName());
String vendorName = "NVIDIA";
ReflectionTestUtils.setField(cmd, "vendorName", vendorName);
assertEquals(vendorName, cmd.getVendorName());
}
@Test
public void getVendorId() {
CreateGpuCardCmd cmd = new CreateGpuCardCmd();
assertNull(cmd.getVendorId());
String vendorId = "10de"; // NVIDIA vendor ID
ReflectionTestUtils.setField(cmd, "vendorId", vendorId);
assertEquals(vendorId, cmd.getVendorId());
}
@Test
public void getVideoRam() {
CreateGpuCardCmd cmd = new CreateGpuCardCmd();
assertNull(cmd.getVideoRam());
Long videoRam = 8192L; // 8 GB
ReflectionTestUtils.setField(cmd, "videoRam", videoRam);
assertEquals(videoRam, cmd.getVideoRam());
}
@Test
public void getEntityOwnerId() {
CreateGpuCardCmd cmd = new CreateGpuCardCmd();
assertEquals(Account.ACCOUNT_ID_SYSTEM, cmd.getEntityOwnerId());
}
}

View File

@ -0,0 +1,100 @@
/*
* 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.apache.cloudstack.gpu.GpuDevice;
import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class CreateGpuDeviceCmdTest {
@Test
public void getHostId() {
CreateGpuDeviceCmd cmd = new CreateGpuDeviceCmd();
assertNull(cmd.getHostId());
Long hostId = 1L;
ReflectionTestUtils.setField(cmd, "hostId", hostId);
assertEquals(hostId, cmd.getHostId());
}
@Test
public void getBusAddress() {
CreateGpuDeviceCmd cmd = new CreateGpuDeviceCmd();
assertNull(cmd.getBusAddress());
String busAddress = "0000:00:1f.6";
ReflectionTestUtils.setField(cmd, "busAddress", busAddress);
assertEquals(busAddress, cmd.getBusAddress());
}
@Test
public void getGpuCardId() {
CreateGpuDeviceCmd cmd = new CreateGpuDeviceCmd();
assertNull(cmd.getGpuCardId());
Long gpuCardId = 1L;
ReflectionTestUtils.setField(cmd, "gpuCardId", gpuCardId);
assertEquals(gpuCardId, cmd.getGpuCardId());
}
@Test
public void getVgpuProfileId() {
CreateGpuDeviceCmd cmd = new CreateGpuDeviceCmd();
assertNull(cmd.getVgpuProfileId());
Long vgpuProfileId = 1L;
ReflectionTestUtils.setField(cmd, "vgpuProfileId", vgpuProfileId);
assertEquals(vgpuProfileId, cmd.getVgpuProfileId());
}
@Test
public void getType() {
CreateGpuDeviceCmd cmd = new CreateGpuDeviceCmd();
assertEquals(GpuDevice.DeviceType.PCI, cmd.getType());
String type = "MDEV";
ReflectionTestUtils.setField(cmd, "type", type);
assertEquals(GpuDevice.DeviceType.MDEV, cmd.getType());
}
@Test
public void getParentGpuDeviceId() {
CreateGpuDeviceCmd cmd = new CreateGpuDeviceCmd();
assertNull(cmd.getParentGpuDeviceId());
Long parentGpuDeviceId = 1L;
ReflectionTestUtils.setField(cmd, "parentGpuDeviceId", parentGpuDeviceId);
assertEquals(parentGpuDeviceId, cmd.getParentGpuDeviceId());
}
@Test
public void getNumaNode() {
CreateGpuDeviceCmd cmd = new CreateGpuDeviceCmd();
assertEquals("-1", cmd.getNumaNode());
String numaNode = "0";
ReflectionTestUtils.setField(cmd, "numaNode", numaNode);
assertEquals(numaNode, cmd.getNumaNode());
}
@Test
public void getEntityOwnerId() {
CreateGpuDeviceCmd cmd = new CreateGpuDeviceCmd();
assertEquals(Account.ACCOUNT_ID_SYSTEM, cmd.getEntityOwnerId());
}
}

View File

@ -0,0 +1,108 @@
/*
* 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class CreateVgpuProfileCmdTest {
@Test
public void getName() {
CreateVgpuProfileCmd cmd = new CreateVgpuProfileCmd();
assertNull(cmd.getName());
String name = "Test VGPU Profile";
ReflectionTestUtils.setField(cmd, "name", name);
assertEquals(name, cmd.getName());
}
@Test
public void getDescription() {
CreateVgpuProfileCmd cmd = new CreateVgpuProfileCmd();
assertNull(cmd.getDescription());
String description = "Test VGPU Profile Description";
ReflectionTestUtils.setField(cmd, "description", description);
assertEquals(description, cmd.getDescription());
}
@Test
public void getCardId() {
CreateVgpuProfileCmd cmd = new CreateVgpuProfileCmd();
assertNull(cmd.getCardId());
Long cardId = 1L;
ReflectionTestUtils.setField(cmd, "cardId", cardId);
assertEquals(cardId, cmd.getCardId());
}
@Test
public void getMaxVgpuPerPgpu() {
CreateVgpuProfileCmd cmd = new CreateVgpuProfileCmd();
assertNull(cmd.getMaxVgpuPerPgpu());
Long maxVgpuPerPgpu = 8L;
ReflectionTestUtils.setField(cmd, "maxVgpuPerPgpu", maxVgpuPerPgpu);
assertEquals(maxVgpuPerPgpu, cmd.getMaxVgpuPerPgpu());
}
@Test
public void getVideoRam() {
CreateVgpuProfileCmd cmd = new CreateVgpuProfileCmd();
assertNull(cmd.getVideoRam());
Long videoRam = 8192L; // 8 GB
ReflectionTestUtils.setField(cmd, "videoRam", videoRam);
assertEquals(videoRam, cmd.getVideoRam());
}
@Test
public void getMaxHeads() {
CreateVgpuProfileCmd cmd = new CreateVgpuProfileCmd();
assertNull(cmd.getMaxHeads());
Long maxHeads = 2L;
ReflectionTestUtils.setField(cmd, "maxHeads", maxHeads);
assertEquals(maxHeads, cmd.getMaxHeads());
}
@Test
public void getMaxResolutionX() {
CreateVgpuProfileCmd cmd = new CreateVgpuProfileCmd();
assertNull(cmd.getMaxResolutionX());
Long maxResolutionX = 1920L; // 1920 pixels
ReflectionTestUtils.setField(cmd, "maxResolutionX", maxResolutionX);
assertEquals(maxResolutionX, cmd.getMaxResolutionX());
}
@Test
public void getMaxResolutionY() {
CreateVgpuProfileCmd cmd = new CreateVgpuProfileCmd();
assertNull(cmd.getMaxResolutionY());
Long maxResolutionY = 1080L; // 1080 pixels
ReflectionTestUtils.setField(cmd, "maxResolutionY", maxResolutionY);
assertEquals(maxResolutionY, cmd.getMaxResolutionY());
}
@Test
public void getEntityOwnerId() {
CreateVgpuProfileCmd cmd = new CreateVgpuProfileCmd();
assertEquals(Account.ACCOUNT_ID_SYSTEM, cmd.getEntityOwnerId());
}
}

View File

@ -0,0 +1,45 @@
/*
* 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class DeleteGpuCardCmdTest {
@Test
public void getId() {
DeleteGpuCardCmd cmd = new DeleteGpuCardCmd();
assertNull(cmd.getId());
Long id = 1L;
ReflectionTestUtils.setField(cmd, "id", id);
assertEquals(id, cmd.getId());
}
@Test
public void getEntityOwnerId() {
CreateVgpuProfileCmd cmd = new CreateVgpuProfileCmd();
assertEquals(Account.ACCOUNT_ID_SYSTEM, cmd.getEntityOwnerId());
}
}

View File

@ -0,0 +1,47 @@
/*
* 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class DeleteGpuDeviceCmdTest {
@Test
public void getIds() {
DeleteGpuDeviceCmd cmd = new DeleteGpuDeviceCmd();
assertNull(cmd.getIds());
List<Long> ids = List.of(1L, 2L, 3L);
ReflectionTestUtils.setField(cmd, "ids", ids);
assertEquals(ids, cmd.getIds());
}
@Test
public void getEntityOwnerId() {
DeleteGpuDeviceCmd cmd = new DeleteGpuDeviceCmd();
assertEquals(Account.ACCOUNT_ID_SYSTEM, cmd.getEntityOwnerId());
}
}

View File

@ -0,0 +1,45 @@
/*
* 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class DeleteVgpuProfileCmdTest {
@Test
public void getId() {
DeleteVgpuProfileCmd cmd = new DeleteVgpuProfileCmd();
assertNull(cmd.getId());
Long id = 1L;
ReflectionTestUtils.setField(cmd, "id", id);
assertEquals(id, cmd.getId());
}
@Test
public void getEntityOwnerId() {
DeleteVgpuProfileCmd cmd = new DeleteVgpuProfileCmd();
assertEquals(Account.ACCOUNT_ID_SYSTEM, cmd.getEntityOwnerId());
}
}

View File

@ -0,0 +1,38 @@
/*
* 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.api.command.admin.gpu;
import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class DiscoverGpuDevicesCmdTest {
@Test
public void getId() {
DiscoverGpuDevicesCmd cmd = new DiscoverGpuDevicesCmd();
assertNull(cmd.getId());
Long id = 1L;
ReflectionTestUtils.setField(cmd, "id", id);
assertEquals(id, cmd.getId());
}
}

View File

@ -0,0 +1,65 @@
/*
* 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.api.command.admin.gpu;
import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class ListGpuDevicesCmdByAdminTest {
@Test
public void getId() {
ListGpuDevicesCmdByAdmin cmd = new ListGpuDevicesCmdByAdmin();
assertNull(cmd.getId());
Long id = 1L;
ReflectionTestUtils.setField(cmd, "id", id);
assertEquals(id, cmd.getId());
}
@Test
public void getHostId() {
ListGpuDevicesCmdByAdmin cmd = new ListGpuDevicesCmdByAdmin();
assertNull(cmd.getHostId());
Long hostId = 1L;
ReflectionTestUtils.setField(cmd, "hostId", hostId);
assertEquals(hostId, cmd.getHostId());
}
@Test
public void getGpuCardId() {
ListGpuDevicesCmdByAdmin cmd = new ListGpuDevicesCmdByAdmin();
assertNull(cmd.getGpuCardId());
Long gpuCardId = 1L;
ReflectionTestUtils.setField(cmd, "gpuCardId", gpuCardId);
assertEquals(gpuCardId, cmd.getGpuCardId());
}
@Test
public void getVgpuProfileId() {
ListGpuDevicesCmdByAdmin cmd = new ListGpuDevicesCmdByAdmin();
assertNull(cmd.getVgpuProfileId());
Long vgpuProfileId = 1L;
ReflectionTestUtils.setField(cmd, "vgpuProfileId", vgpuProfileId);
assertEquals(vgpuProfileId, cmd.getVgpuProfileId());
}
}

View File

@ -0,0 +1,47 @@
/*
* 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class ManageGpuDeviceCmdTest {
@Test
public void getIds() {
ManageGpuDeviceCmd cmd = new ManageGpuDeviceCmd();
assertNull(cmd.getIds());
List<Long> ids = List.of(1L, 2L, 3L);
ReflectionTestUtils.setField(cmd, "ids", ids);
assertEquals(ids, cmd.getIds());
}
@Test
public void getEntityOwnerId() {
ManageGpuDeviceCmd cmd = new ManageGpuDeviceCmd();
assertEquals(Account.ACCOUNT_ID_SYSTEM, cmd.getEntityOwnerId());
}
}

View File

@ -0,0 +1,47 @@
/*
* 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class UnmanageGpuDeviceCmdTest {
@Test
public void getIds() {
UnmanageGpuDeviceCmd cmd = new UnmanageGpuDeviceCmd();
assertNull(cmd.getIds());
List<Long> ids = List.of(1L, 2L, 3L);
ReflectionTestUtils.setField(cmd, "ids", ids);
assertEquals(ids, cmd.getIds());
}
@Test
public void getEntityOwnerId() {
UnmanageGpuDeviceCmd cmd = new UnmanageGpuDeviceCmd();
assertEquals(Account.ACCOUNT_ID_SYSTEM, cmd.getEntityOwnerId());
}
}

View File

@ -0,0 +1,72 @@
/*
* 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class UpdateGpuCardCmdTest {
@Test
public void getId() {
UpdateGpuCardCmd cmd = new UpdateGpuCardCmd();
assertNull(cmd.getId());
Long id = 1L;
ReflectionTestUtils.setField(cmd, "id", id);
assertEquals(id, cmd.getId());
}
@Test
public void getDeviceName() {
UpdateGpuCardCmd cmd = new UpdateGpuCardCmd();
assertNull(cmd.getDeviceName());
String deviceName = "GPU-1234";
ReflectionTestUtils.setField(cmd, "deviceName", deviceName);
assertEquals(deviceName, cmd.getDeviceName());
}
@Test
public void getName() {
UpdateGpuCardCmd cmd = new UpdateGpuCardCmd();
assertNull(cmd.getName());
String name = "Test GPU Card";
ReflectionTestUtils.setField(cmd, "name", name);
assertEquals(name, cmd.getName());
}
@Test
public void getVendorName() {
UpdateGpuCardCmd cmd = new UpdateGpuCardCmd();
assertNull(cmd.getVendorName());
String vendorName = "NVIDIA";
ReflectionTestUtils.setField(cmd, "vendorName", vendorName);
assertEquals(vendorName, cmd.getVendorName());
}
@Test
public void getEntityOwnerId() {
UpdateGpuCardCmd cmd = new UpdateGpuCardCmd();
assertEquals(Account.ACCOUNT_ID_SYSTEM, cmd.getEntityOwnerId());
}
}

View File

@ -0,0 +1,91 @@
/*
* 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.apache.cloudstack.gpu.GpuDevice;
import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class UpdateGpuDeviceCmdTest {
@Test
public void getId() {
UpdateGpuDeviceCmd cmd = new UpdateGpuDeviceCmd();
assertNull(cmd.getId());
Long id = 1L;
ReflectionTestUtils.setField(cmd, "id", id);
assertEquals(id, cmd.getId());
}
@Test
public void getGpuCardId() {
UpdateGpuDeviceCmd cmd = new UpdateGpuDeviceCmd();
assertNull(cmd.getGpuCardId());
Long gpuCardId = 1L;
ReflectionTestUtils.setField(cmd, "gpuCardId", gpuCardId);
assertEquals(gpuCardId, cmd.getGpuCardId());
}
@Test
public void getVgpuProfileId() {
UpdateGpuDeviceCmd cmd = new UpdateGpuDeviceCmd();
assertNull(cmd.getVgpuProfileId());
Long vgpuProfileId = 1L;
ReflectionTestUtils.setField(cmd, "vgpuProfileId", vgpuProfileId);
assertEquals(vgpuProfileId, cmd.getVgpuProfileId());
}
@Test
public void getType() {
UpdateGpuDeviceCmd cmd = new UpdateGpuDeviceCmd();
assertNull(cmd.getType());
String type = "MDEV";
ReflectionTestUtils.setField(cmd, "type", type);
assertEquals(GpuDevice.DeviceType.MDEV, cmd.getType());
}
@Test
public void getParentGpuDeviceId() {
UpdateGpuDeviceCmd cmd = new UpdateGpuDeviceCmd();
assertNull(cmd.getParentGpuDeviceId());
Long parentGpuDeviceId = 1L;
ReflectionTestUtils.setField(cmd, "parentGpuDeviceId", parentGpuDeviceId);
assertEquals(parentGpuDeviceId, cmd.getParentGpuDeviceId());
}
@Test
public void getNumaNode() {
UpdateGpuDeviceCmd cmd = new UpdateGpuDeviceCmd();
assertNull(cmd.getNumaNode());
String numaNode = "0";
ReflectionTestUtils.setField(cmd, "numaNode", numaNode);
assertEquals(numaNode, cmd.getNumaNode());
}
@Test
public void getEntityOwnerId() {
UpdateGpuDeviceCmd cmd = new UpdateGpuDeviceCmd();
assertEquals(Account.ACCOUNT_ID_SYSTEM, cmd.getEntityOwnerId());
}
}

View File

@ -0,0 +1,108 @@
/*
* 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.api.command.admin.gpu;
import com.cloud.user.Account;
import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class UpdateVgpuProfileCmdTest {
@Test
public void getId() {
UpdateVgpuProfileCmd cmd = new UpdateVgpuProfileCmd();
assertNull(cmd.getId());
Long id = 1L;
ReflectionTestUtils.setField(cmd, "id", id);
assertEquals(id, cmd.getId());
}
@Test
public void getProfileName() {
UpdateVgpuProfileCmd cmd = new UpdateVgpuProfileCmd();
assertNull(cmd.getProfileName());
String profileName = "Test VGPU Profile";
ReflectionTestUtils.setField(cmd, "profileName", profileName);
assertEquals(profileName, cmd.getProfileName());
}
@Test
public void getDescription() {
UpdateVgpuProfileCmd cmd = new UpdateVgpuProfileCmd();
assertNull(cmd.getDescription());
String description = "Test VGPU Profile Description";
ReflectionTestUtils.setField(cmd, "description", description);
assertEquals(description, cmd.getDescription());
}
@Test
public void getMaxVgpuPerPgpu() {
UpdateVgpuProfileCmd cmd = new UpdateVgpuProfileCmd();
assertNull(cmd.getMaxVgpuPerPgpu());
Long maxVgpuPerPgpu = 8L;
ReflectionTestUtils.setField(cmd, "maxVgpuPerPgpu", maxVgpuPerPgpu);
assertEquals(maxVgpuPerPgpu, cmd.getMaxVgpuPerPgpu());
}
@Test
public void getVideoRam() {
UpdateVgpuProfileCmd cmd = new UpdateVgpuProfileCmd();
assertNull(cmd.getVideoRam());
Long videoRam = 8192L; // 8 GB
ReflectionTestUtils.setField(cmd, "videoRam", videoRam);
assertEquals(videoRam, cmd.getVideoRam());
}
@Test
public void getMaxHeads() {
UpdateVgpuProfileCmd cmd = new UpdateVgpuProfileCmd();
assertNull(cmd.getMaxHeads());
Long maxHeads = 2L;
ReflectionTestUtils.setField(cmd, "maxHeads", maxHeads);
assertEquals(maxHeads, cmd.getMaxHeads());
}
@Test
public void getMaxResolutionX() {
UpdateVgpuProfileCmd cmd = new UpdateVgpuProfileCmd();
assertNull(cmd.getMaxResolutionX());
Long maxResolutionX = 1920L; // Example resolution
ReflectionTestUtils.setField(cmd, "maxResolutionX", maxResolutionX);
assertEquals(maxResolutionX, cmd.getMaxResolutionX());
}
@Test
public void getMaxResolutionY() {
UpdateVgpuProfileCmd cmd = new UpdateVgpuProfileCmd();
assertNull(cmd.getMaxResolutionY());
Long maxResolutionY = 1080L; // Example resolution
ReflectionTestUtils.setField(cmd, "maxResolutionY", maxResolutionY);
assertEquals(maxResolutionY, cmd.getMaxResolutionY());
}
@Test
public void getEntityOwnerId() {
UpdateVgpuProfileCmd cmd = new UpdateVgpuProfileCmd();
assertEquals(Account.ACCOUNT_ID_SYSTEM, cmd.getEntityOwnerId());
}
}

View File

@ -78,4 +78,23 @@ public class CreateServiceOfferingCmdTest {
ReflectionTestUtils.setField(createServiceOfferingCmd, "leaseExpiryAction", "Unknown");
Assert.assertEquals(null, createServiceOfferingCmd.getLeaseExpiryAction());
}
@Test
public void testGetVgpuProfileId() {
ReflectionTestUtils.setField(createServiceOfferingCmd, "vgpuProfileId", 10L);
Assert.assertEquals(10L, createServiceOfferingCmd.getVgpuProfileId().longValue());
}
@Test
public void testGetGpuCount() {
ReflectionTestUtils.setField(createServiceOfferingCmd, "gpuCount", 2);
Assert.assertEquals(2, createServiceOfferingCmd.getGpuCount().intValue());
}
@Test
public void testGetGpuDisplay() {
ReflectionTestUtils.setField(createServiceOfferingCmd, "gpuDisplay", true);
Assert.assertTrue(createServiceOfferingCmd.getGpuDisplay());
}
}

View File

@ -0,0 +1,82 @@
/*
* 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.api.command.user.gpu;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;
public class ListGpuCardsCmdTest {
@Test
public void getId() {
ListGpuCardsCmd cmd = new ListGpuCardsCmd();
Assert.assertNull(cmd.getId());
Long id = 1L;
ReflectionTestUtils.setField(cmd, "id", id);
Assert.assertEquals(id, cmd.getId());
}
@Test
public void getVendorName() {
ListGpuCardsCmd cmd = new ListGpuCardsCmd();
Assert.assertNull(cmd.getVendorName());
String vendorName = "vendor name";
ReflectionTestUtils.setField(cmd, "vendorName", vendorName);
Assert.assertEquals(vendorName, cmd.getVendorName());
}
@Test
public void getVendorId() {
ListGpuCardsCmd cmd = new ListGpuCardsCmd();
Assert.assertNull(cmd.getVendorId());
String vendorId = "vendor id";
ReflectionTestUtils.setField(cmd, "vendorId", vendorId);
Assert.assertEquals(vendorId, cmd.getVendorId());
}
@Test
public void getDeviceId() {
ListGpuCardsCmd cmd = new ListGpuCardsCmd();
Assert.assertNull(cmd.getDeviceId());
String deviceId = "device id";
ReflectionTestUtils.setField(cmd, "deviceId", deviceId);
Assert.assertEquals(deviceId, cmd.getDeviceId());
}
@Test
public void getDeviceName() {
ListGpuCardsCmd cmd = new ListGpuCardsCmd();
Assert.assertNull(cmd.getDeviceName());
String deviceName = "device name";
ReflectionTestUtils.setField(cmd, "deviceName", deviceName);
Assert.assertEquals(deviceName, cmd.getDeviceName());
}
@Test
public void getActiveOnly() {
ListGpuCardsCmd cmd = new ListGpuCardsCmd();
Assert.assertFalse(cmd.getActiveOnly());
Boolean activeOnly = true;
ReflectionTestUtils.setField(cmd, "activeOnly", activeOnly);
Assert.assertEquals(activeOnly, cmd.getActiveOnly());
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.api.command.user.gpu;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;
public class ListGpuDevicesCmdTest {
@Test
public void getVmId() {
ListGpuDevicesCmd cmd = new ListGpuDevicesCmd();
Assert.assertNull(cmd.getVmId());
Long vmId = 1L;
ReflectionTestUtils.setField(cmd, "vmId", vmId);
Assert.assertEquals(vmId, cmd.getVmId());
}
}

View File

@ -0,0 +1,63 @@
/*
* 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.api.command.user.gpu;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;
public class ListVgpuProfilesCmdTest {
@Test
public void getId() {
ListVgpuProfilesCmd cmd = new ListVgpuProfilesCmd();
Assert.assertNull(cmd.getId());
Long id = 1L;
ReflectionTestUtils.setField(cmd, "id", id);
Assert.assertEquals(id, cmd.getId());
}
@Test
public void getName() {
ListVgpuProfilesCmd cmd = new ListVgpuProfilesCmd();
Assert.assertNull(cmd.getName());
String name = "Test VGPU Profile";
ReflectionTestUtils.setField(cmd, "name", name);
Assert.assertEquals(name, cmd.getName());
}
@Test
public void getCardId() {
ListVgpuProfilesCmd cmd = new ListVgpuProfilesCmd();
Assert.assertNull(cmd.getCardId());
Long cardId = 1L;
ReflectionTestUtils.setField(cmd, "cardId", cardId);
Assert.assertEquals(cardId, cmd.getCardId());
}
@Test
public void getActiveOnly() {
ListVgpuProfilesCmd cmd = new ListVgpuProfilesCmd();
Assert.assertFalse(cmd.getActiveOnly());
Boolean activeOnly = true;
ReflectionTestUtils.setField(cmd, "activeOnly", activeOnly);
Assert.assertEquals(activeOnly, cmd.getActiveOnly());
}
}

View File

@ -19,7 +19,9 @@
package com.cloud.agent.api;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import com.cloud.agent.api.LogLevel.Log4jLevel;
@ -27,6 +29,7 @@ import com.cloud.agent.api.LogLevel.Log4jLevel;
public class GetGPUStatsAnswer extends Answer {
private HashMap<String, HashMap<String, VgpuTypesInfo>> groupDetails;
private List<VgpuTypesInfo> gpuDevices = new ArrayList<>();
public GetGPUStatsAnswer(final GetGPUStatsCommand cmd, final HashMap<String, HashMap<String, VgpuTypesInfo>> groupDetails) {
super(cmd);
@ -37,7 +40,21 @@ public class GetGPUStatsAnswer extends Answer {
super(cmd, success, details);
}
public GetGPUStatsAnswer(final GetGPUStatsCommand cmd, final List<VgpuTypesInfo> gpuDevices) {
super(cmd);
this.gpuDevices = gpuDevices;
}
public HashMap<String, HashMap<String, VgpuTypesInfo>> getGroupDetails() {
return groupDetails;
}
public List<VgpuTypesInfo> getGpuDevices() {
return gpuDevices;
}
public void setGpuDevices(List<VgpuTypesInfo> gpuDevices) {
this.gpuDevices = gpuDevices;
}
}

View File

@ -45,6 +45,7 @@ public class StartupRoutingCommand extends StartupCommand {
List<String> hostTags = new ArrayList<String>();
String hypervisorVersion;
HashMap<String, HashMap<String, VgpuTypesInfo>> groupDetails = new HashMap<String, HashMap<String, VgpuTypesInfo>>();
List<VgpuTypesInfo> gpuDevices = new ArrayList<>();
private Boolean hostHealthCheckResult;
public StartupRoutingCommand() {
@ -179,7 +180,7 @@ public class StartupRoutingCommand extends StartupCommand {
this.hostTags = hostTags;
}
public HashMap<String, HashMap<String, VgpuTypesInfo>> getGpuGroupDetails() {
public HashMap<String, HashMap<String, VgpuTypesInfo>> getGpuGroupDetails() {
return groupDetails;
}
@ -187,6 +188,14 @@ public class StartupRoutingCommand extends StartupCommand {
this.groupDetails = groupDetails;
}
public List<VgpuTypesInfo> getGpuDevices() {
return gpuDevices;
}
public void setGpuDevices(List<VgpuTypesInfo> gpuDevices) {
this.gpuDevices = gpuDevices;
}
public boolean getSupportsClonedVolumes() {
return supportsClonedVolumes;
}

View File

@ -50,5 +50,4 @@ public interface Discoverer extends Adapter {
public void putParam(Map<String, String> params);
ServerResource reloadResource(HostVO host);
}

View File

@ -21,8 +21,12 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.cloud.offering.ServiceOffering;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo;
import com.cloud.gpu.VgpuProfileVO;
import com.cloud.vm.VirtualMachine;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
@ -194,29 +198,34 @@ public interface ResourceManager extends ResourceService, Configurable {
*/
boolean isHostGpuEnabled(long hostId);
/**
* Check if host has GPU devices available
* @param hostId the host to be checked
* @param groupName: gpuCard name
* @param vgpuType the VGPU type
* @return true when the host has the capacity with given VGPU type
*/
boolean isGPUDeviceAvailable(Host host, String groupName, String vgpuType);
boolean isGPUDeviceAvailable(ServiceOffering offering, Host host, Long vmId);
/**
* Get available GPU device
* @param hostId the host to be checked
* @param groupName: gpuCard name
* @param vgpuType the VGPU type
*
* @param vm the vm for which GPU device is requested
* @param vgpuProfile the VGPU profile
* @param gpuCount
* @return GPUDeviceTO[]
*/
GPUDeviceTO getGPUDevice(VirtualMachine vm, long hostId, VgpuProfileVO vgpuProfile, int gpuCount);
/**
* Get available GPU device
*
* @param hostId the host to be checked
* @param groupName gpuCard name
* @param vgpuType the VGPU type
* @return GPUDeviceTO[]
*/
GPUDeviceTO getGPUDevice(long hostId, String groupName, String vgpuType);
/**
* Return listof available GPU devices
* @param hostId, the host to be checked
* @param groupName: gpuCard name
* @param vgpuType the VGPU type
*
* @param hostId the host to be checked
* @param groupName gpuCard name
* @param vgpuType the VGPU type
* @return List of HostGpuGroupsVO.
*/
List<HostGpuGroupsVO> listAvailableGPUDevice(long hostId, String groupName, String vgpuType);
@ -228,6 +237,16 @@ public interface ResourceManager extends ResourceService, Configurable {
*/
void updateGPUDetails(long hostId, HashMap<String, HashMap<String, VgpuTypesInfo>> groupDetails);
/**
* Update GPU device details (post VM deployment)
*
* @param vm the VirtualMachine object
* @param gpuDeviceTO GPU device details
*/
void updateGPUDetailsForVmStop(VirtualMachine vm, GPUDeviceTO gpuDeviceTO);
void updateGPUDetailsForVmStart(long hostId, long vmId, GPUDeviceTO gpuDevice);
/**
* Get GPU details for a host
* @param host, the Host object

View File

@ -87,6 +87,7 @@ import org.apache.cloudstack.framework.jobs.impl.VmWorkJobVO;
import org.apache.cloudstack.framework.messagebus.MessageBus;
import org.apache.cloudstack.framework.messagebus.MessageDispatcher;
import org.apache.cloudstack.framework.messagebus.MessageHandler;
import org.apache.cloudstack.gpu.GpuService;
import org.apache.cloudstack.jobs.JobInfo;
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
import org.apache.cloudstack.reservation.dao.ReservationDao;
@ -395,6 +396,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
@Inject
private VolumeOrchestrationService volumeMgr;
@Inject
private GpuService gpuService;
@Inject
private DeploymentPlanningManager _dpMgr;
@Inject
private MessageBus _messageBus;
@ -1530,7 +1533,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
final GPUDeviceTO gpuDevice = startAnswer.getVirtualMachine().getGpuDevice();
if (gpuDevice != null) {
_resourceMgr.updateGPUDetails(destHostId, gpuDevice.getGroupDetails());
_resourceMgr.updateGPUDetailsForVmStart(destHostId, vm.getId(), gpuDevice);
}
if (vmInstanceDetailsDao.findDetail(vm.getId(), VmDetailConstants.DEPLOY_VM) != null) {
@ -2123,9 +2126,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
}
final GPUDeviceTO gpuDevice = stop.getGpuDevice();
if (gpuDevice != null) {
_resourceMgr.updateGPUDetails(vm.getHostId(), gpuDevice.getGroupDetails());
}
_resourceMgr.updateGPUDetailsForVmStop(vm, gpuDevice);
if (!answer.getResult()) {
final String details = answer.getDetails();
logger.debug("Unable to stop VM due to {}", details);
@ -2454,9 +2455,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
}
vmGuru.finalizeStop(profile, answer);
final GPUDeviceTO gpuDevice = stop.getGpuDevice();
if (gpuDevice != null) {
_resourceMgr.updateGPUDetails(vm.getHostId(), gpuDevice.getGroupDetails());
}
_resourceMgr.updateGPUDetailsForVmStop(vm, gpuDevice);
} else {
throw new CloudRuntimeException("Invalid answer received in response to a StopCommand on " + vm.instanceName);
}
@ -2559,6 +2558,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
_reservationDao.setResourceId(Resource.ResourceType.user_vm, null);
_reservationDao.setResourceId(Resource.ResourceType.cpu, null);
_reservationDao.setResourceId(Resource.ResourceType.memory, null);
_reservationDao.setResourceId(Resource.ResourceType.gpu, null);
}
return _stateMachine.transitTo(vm, e, new Pair<>(vm.getHostId(), hostId), _vmDao);
}
@ -2577,6 +2577,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
deleteVMSnapshots(vm, expunge);
gpuService.deallocateAllGpuDevicesForVm(vm.getId());
Transaction.execute(new TransactionCallbackWithExceptionNoReturn<CloudRuntimeException>() {
@Override
public void doInTransactionWithoutResult(final TransactionStatus status) throws CloudRuntimeException {
@ -3147,6 +3149,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
logger.info("Migration was unsuccessful. Cleaning up: {}", vm);
_networkMgr.rollbackNicForMigration(vmSrc, profile);
volumeMgr.release(vm.getId(), dstHostId);
// deallocate GPU devices for the VM on the destination host
gpuService.deallocateGpuDevicesForVmOnHost(vm.getId(), dstHostId);
_alertMgr.sendAlert(alertType, fromHost.getDataCenterId(), fromHost.getPodId(),
"Unable to migrate vm " + vm.getInstanceName() + " from host " + fromHost.getName() + " in zone " + dest.getDataCenter().getName() + " and pod " +
@ -3165,6 +3169,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
} else {
_networkMgr.commitNicForMigration(vmSrc, profile);
volumeMgr.release(vm.getId(), srcHostId);
// deallocate GPU devices for the VM on the src host after migration is complete
gpuService.deallocateGpuDevicesForVmOnHost(vm.getId(), srcHostId);
_networkMgr.setHypervisorHostname(profile, dest, true);
recreateCheckpointsKvmOnVmAfterMigration(vm, dstHostId);
@ -3963,6 +3969,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
affectedVms.add(vm.getId());
_securityGroupManager.scheduleRulesetUpdateToHosts(affectedVms, true, null);
}
if (vmTo.getGpuDevice() != null) {
_resourceMgr.updateGPUDetailsForVmStart(host.getId(), vm.getId(), vmTo.getGpuDevice());
}
return;
}

View File

@ -43,6 +43,7 @@ import java.util.Random;
import java.util.UUID;
import java.util.stream.Collectors;
import com.cloud.resource.ResourceManager;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
@ -230,6 +231,8 @@ public class VirtualMachineManagerImplTest {
@Mock
private EntityManager _entityMgr;
@Mock
private ResourceManager _resourceMgr;
@Mock
private DeploymentPlanningManager _dpMgr;
@Mock
private HypervisorGuruManager _hvGuruMgr;

View File

@ -62,20 +62,6 @@ public interface ResourceCountDao extends GenericDao<ResourceCountVO, Long> {
long removeEntriesByOwner(long ownerId, ResourceOwnerType ownerType);
/**
* Counts the number of CPU cores allocated for the given account.
*
* Side note: This method is not using the "resource_count" table. It is executing the actual count instead.
*/
long countCpuNumberAllocatedToAccount(long accountId);
/**
* Counts the amount of memory allocated for the given account.
*
* Side note: This method is not using the "resource_count" table. It is executing the actual count instead.
*/
long countMemoryAllocatedToAccount(long accountId);
void removeResourceCountsForNonMatchingTags(Long ownerId, ResourceOwnerType ownerType, List<ResourceType> types, List<String> tags);
List<ResourceCountVO> lockRows(Set<Long> ids);

View File

@ -339,19 +339,6 @@ public class ResourceCountDaoImpl extends GenericDaoBase<ResourceCountVO, Long>
+ " left join vm_instance_details vmd on vmd.vm_id = vm.id and vmd.name = '%s' "
+ " where vm.type = 'User' and state not in ('Destroyed', 'Error', 'Expunging') and display_vm = true and account_id = ? ";
@Override
public long countCpuNumberAllocatedToAccount(long accountId) {
String sqlCountCpuNumberAllocatedToAccount = String.format(baseSqlCountComputingResourceAllocatedToAccount, ResourceType.cpu, ResourceType.cpu, "cpuNumber");
return executeSqlCountComputingResourcesForAccount(accountId, sqlCountCpuNumberAllocatedToAccount);
}
@Override
public long countMemoryAllocatedToAccount(long accountId) {
String serviceOfferingRamSizeField = "ram_size";
String sqlCountCpuNumberAllocatedToAccount = String.format(baseSqlCountComputingResourceAllocatedToAccount, serviceOfferingRamSizeField, serviceOfferingRamSizeField, "memory");
return executeSqlCountComputingResourcesForAccount(accountId, sqlCountCpuNumberAllocatedToAccount);
}
private long executeSqlCountComputingResourcesForAccount(long accountId, String sqlCountComputingResourcesAllocatedToAccount) {
TransactionLegacy tx = TransactionLegacy.currentTxn();
try {

View File

@ -0,0 +1,147 @@
// 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 com.cloud.gpu;
import com.cloud.utils.db.GenericDao;
import org.apache.cloudstack.gpu.GpuCard;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
import java.util.UUID;
@Entity
@Table(name = "gpu_card")
public class GpuCardVO implements GpuCard {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@Column(name = "uuid")
private String uuid;
@Column(name = "device_id")
private String deviceId;
@Column(name = "device_name")
private String deviceName;
@Column(name = "name")
private String name;
@Column(name = "vendor_name")
private String vendorName;
@Column(name = "vendor_id")
private String vendorId;
@Column(name = GenericDao.CREATED_COLUMN)
private Date created;
public GpuCardVO() {
this.uuid = UUID.randomUUID().toString();
}
public GpuCardVO(String deviceId, String deviceName, String name, String vendorName, String vendorId) {
this.uuid = UUID.randomUUID().toString();
this.deviceId = deviceId;
this.deviceName = deviceName;
this.name = name;
this.vendorName = vendorName;
this.vendorId = vendorId;
this.created = new Date();
}
@Override
public String toString() {
return String.format("GPUCard %s", ReflectionToStringBuilderUtils.reflectOnlySelectedFields(
this, "id", "uuid", "name", "deviceId", "deviceName", "vendorId", "vendorName"));
}
@Override
public long getId() {
return id;
}
@Override
public String getUuid() {
return uuid;
}
@Override
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
@Override
public String getDeviceName() {
return deviceName;
}
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
@Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String getVendorName() {
return vendorName;
}
public void setVendorName(String vendorName) {
this.vendorName = vendorName;
}
@Override
public String getVendorId() {
return vendorId;
}
public void setVendorId(String vendorId) {
this.vendorId = vendorId;
}
@Override
public Date getCreated() {
return created;
}
@Override
public String getGroupName() {
return "Group of " + getVendorName() + " " + getDeviceName() + " GPUs";
}
}

View File

@ -0,0 +1,200 @@
// 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 com.cloud.gpu;
import org.apache.cloudstack.gpu.GpuDevice;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.UUID;
@Entity
@Table(name = "gpu_device")
public class GpuDeviceVO implements GpuDevice {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@Column(name = "uuid")
private String uuid;
@Column(name = "card_id")
private long cardId;
@Column(name = "vgpu_profile_id")
private long vgpuProfileId;
@Column(name = "bus_address")
private String busAddress;
@Column(name = "host_id")
private long hostId;
@Column(name = "vm_id")
private Long vmId;
@Column(name = "type")
@Enumerated(value = EnumType.STRING)
private DeviceType type = DeviceType.PCI;
@Column(name = "state")
@Enumerated(value = EnumType.STRING)
private State state = State.Free;
@Column(name = "managed_state")
@Enumerated(value = EnumType.STRING)
private ManagedState managedState = ManagedState.Managed;
@Column(name = "parent_gpu_device_id")
private Long parentGpuDeviceId;
@Column(name = "numa_node")
private String numaNode;
@Column(name = "pci_root")
private String pciRoot;
public GpuDeviceVO() {
this.uuid = UUID.randomUUID().toString();
}
public GpuDeviceVO(long cardId, long vgpuProfileId, String busAddress, long hostId, Long parentGpuDeviceId,
String numaNode, String pciRoot) {
this.uuid = UUID.randomUUID().toString();
this.cardId = cardId;
this.vgpuProfileId = vgpuProfileId;
this.busAddress = busAddress;
this.hostId = hostId;
this.parentGpuDeviceId = parentGpuDeviceId;
this.numaNode = numaNode;
this.pciRoot = pciRoot;
}
@Override
public String toString() {
return String.format("GpuDevice %s", ReflectionToStringBuilderUtils.reflectOnlySelectedFields(
this, "id", "uuid", "cardId", "vgpuProfileId", "busAddress", "hostId", "vmId",
"parentGpuDeviceId", "numaNode", "pciRoot", "state", "resourceState"));
}
@Override
public long getId() {
return id;
}
public String getUuid() {
return uuid;
}
public long getCardId() {
return cardId;
}
public void setCardId(long cardId) {
this.cardId = cardId;
}
public long getVgpuProfileId() {
return vgpuProfileId;
}
public void setVgpuProfileId(long vgpuProfileId) {
this.vgpuProfileId = vgpuProfileId;
}
public String getBusAddress() {
return busAddress;
}
public void setBusAddress(String busAddress) {
this.busAddress = busAddress;
}
public long getHostId() {
return hostId;
}
public void setHostId(long hostId) {
this.hostId = hostId;
}
@Override
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public DeviceType getType() {
return type;
}
public void setType(DeviceType type) {
this.type = type;
}
public ManagedState getManagedState() {
return managedState;
}
public void setManagedState(ManagedState managedState) {
this.managedState = managedState;
}
public Long getVmId() {
return vmId;
}
public void setVmId(Long vmId) {
this.vmId = vmId;
}
public Long getParentGpuDeviceId() {
return parentGpuDeviceId;
}
public void setParentGpuDeviceId(Long parentGpuDeviceId) {
this.parentGpuDeviceId = parentGpuDeviceId;
}
public String getNumaNode() {
return numaNode;
}
public void setNumaNode(String numaNode) {
this.numaNode = numaNode;
}
public String getPciRoot() {
return pciRoot;
}
public void setPciRoot(String pciRoot) {
this.pciRoot = pciRoot;
}
}

View File

@ -40,19 +40,19 @@ public class VGPUTypesVO implements InternalIdentity {
private String vgpuType;
@Column(name="video_ram")
private long videoRam;
private Long videoRam;
@Column(name="max_heads")
private long maxHeads;
private Long maxHeads;
@Column(name="max_resolution_x")
private long maxResolutionX;
private Long maxResolutionX;
@Column(name="max_resolution_y")
private long maxResolutionY;
private Long maxResolutionY;
@Column(name="max_vgpu_per_pgpu")
private long maxVgpuPerPgpu;
private Long maxVgpuPerPgpu;
@Column(name="remaining_capacity")
private long remainingCapacity;
@ -63,7 +63,7 @@ public class VGPUTypesVO implements InternalIdentity {
protected VGPUTypesVO() {
}
public VGPUTypesVO(long gpuGroupId, String vgpuType, long videoRam, long maxHeads, long maxResolutionX, long maxResolutionY, long maxVgpuPerPgpu,
public VGPUTypesVO(long gpuGroupId, String vgpuType, Long videoRam, Long maxHeads, Long maxResolutionX, Long maxResolutionY, Long maxVgpuPerPgpu,
long remainingCapacity, long maxCapacity) {
this.gpuGroupId = gpuGroupId;
this.vgpuType = vgpuType;
@ -92,43 +92,43 @@ public class VGPUTypesVO implements InternalIdentity {
this.vgpuType = vgpuType;
}
public long getVideoRam() {
public Long getVideoRam() {
return videoRam;
}
public void setVideoRam(long videoRam) {
public void setVideoRam(Long videoRam) {
this.videoRam = videoRam;
}
public long getMaxHeads() {
public Long getMaxHeads() {
return maxHeads;
}
public void setMaxHeads(long maxHeads) {
public void setMaxHeads(Long maxHeads) {
this.maxHeads = maxHeads;
}
public long getMaxResolutionX() {
public Long getMaxResolutionX() {
return maxResolutionX;
}
public void setMaxResolutionX(long maxResolutionX) {
public void setMaxResolutionX(Long maxResolutionX) {
this.maxResolutionX = maxResolutionX;
}
public long getMaxResolutionY() {
public Long getMaxResolutionY() {
return maxResolutionY;
}
public void setMaxResolutionY(long maxResolutionY) {
public void setMaxResolutionY(Long maxResolutionY) {
this.maxResolutionY = maxResolutionY;
}
public long getMaxVgpuPerPgpu() {
public Long getMaxVgpuPerPgpu() {
return maxVgpuPerPgpu;
}
public void setMaxVgpuPerPgpu(long maxVgpuPerPgpu) {
public void setMaxVgpuPerPgpu(Long maxVgpuPerPgpu) {
this.maxVgpuPerPgpu = maxVgpuPerPgpu;
}

View File

@ -0,0 +1,191 @@
// 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 com.cloud.gpu;
import com.cloud.utils.db.GenericDao;
import org.apache.cloudstack.gpu.VgpuProfile;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
import java.util.UUID;
@Entity
@Table(name = "vgpu_profile")
public class VgpuProfileVO implements VgpuProfile {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@Column(name = "uuid")
private String uuid;
@Column(name = "name")
private String name;
@Column(name = "description")
private String description;
@Column(name = "card_id")
private Long cardId;
@Column(name = "max_vgpu_per_pgpu")
private Long maxVgpuPerPgpu;
@Column(name = "video_ram")
private Long videoRam;
@Column(name = "max_heads")
private Long maxHeads;
@Column(name = "max_resolution_x")
private Long maxResolutionX;
@Column(name = "max_resolution_y")
private Long maxResolutionY;
@Column(name = GenericDao.CREATED_COLUMN)
private Date created;
public VgpuProfileVO() {
this.uuid = UUID.randomUUID().toString();
}
public VgpuProfileVO(String name, String description, Long gpuCardId, Long maxVgpuPerPgpu) {
this.uuid = UUID.randomUUID().toString();
this.name = name;
this.description = description;
this.cardId = gpuCardId;
this.maxVgpuPerPgpu = maxVgpuPerPgpu;
this.created = new Date();
}
public VgpuProfileVO(String name, String description, Long gpuCardId, Long maxVgpuPerPgpu, Long videoRam, Long maxHeads, Long maxResolutionX, Long maxResolutionY) {
this.uuid = UUID.randomUUID().toString();
this.name = name;
this.description = description;
this.cardId = gpuCardId;
this.maxVgpuPerPgpu = maxVgpuPerPgpu;
this.videoRam = videoRam;
this.maxHeads = maxHeads;
this.maxResolutionX = maxResolutionX;
this.maxResolutionY = maxResolutionY;
this.created = new Date();
}
@Override
public String toString() {
return String.format("VgpuProfile %s", ReflectionToStringBuilderUtils.reflectOnlySelectedFields(
this, "id", "uuid", "name", "cardId"));
}
@Override
public long getId() {
return id;
}
@Override
public String getUuid() {
return uuid;
}
@Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public Date getCreated() {
return created;
}
@Override
public Long getCardId() {
return cardId;
}
public void setCardId(Long cardId) {
this.cardId = cardId;
}
@Override
public Long getMaxVgpuPerPgpu() {
return maxVgpuPerPgpu;
}
public void setMaxVgpuPerPgpu(Long maxVgpuPerPgpu) {
this.maxVgpuPerPgpu = maxVgpuPerPgpu;
}
@Override
public Long getVideoRam() {
return videoRam;
}
public void setVideoRam(Long videoRam) {
this.videoRam = videoRam;
}
@Override
public Long getMaxHeads() {
return maxHeads;
}
public void setMaxHeads(Long maxHeads) {
this.maxHeads = maxHeads;
}
@Override
public Long getMaxResolutionX() {
return maxResolutionX;
}
public void setMaxResolutionX(Long maxResolutionX) {
this.maxResolutionX = maxResolutionX;
}
@Override
public Long getMaxResolutionY() {
return maxResolutionY;
}
public void setMaxResolutionY(Long maxResolutionY) {
this.maxResolutionY = maxResolutionY;
}
}

View File

@ -0,0 +1,39 @@
// 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 com.cloud.gpu.dao;
import com.cloud.gpu.GpuCardVO;
import com.cloud.utils.Pair;
import com.cloud.utils.db.GenericDao;
import java.util.List;
public interface GpuCardDao extends GenericDao<GpuCardVO, Long> {
/**
* Find GPU card by vendor and device id
*
* @param vendorId the vendor id
* @param deviceId the device id
* @return GpuCardVO
*/
GpuCardVO findByVendorIdAndDeviceId(String vendorId, String deviceId);
Pair<List<GpuCardVO>, Integer> searchAndCountGpuCards(
Long id, String keyword, String vendorId, String vendorName,
String deviceId, String deviceName, boolean activeOnly, Long startIndex, Long pageSize);
}

View File

@ -0,0 +1,122 @@
// 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 com.cloud.gpu.dao;
import com.cloud.gpu.GpuCardVO;
import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
import java.util.List;
@Component
public class GpuCardDaoImpl extends GenericDaoBase<GpuCardVO, Long> implements GpuCardDao {
private final SearchBuilder<GpuCardVO> allFieldSearch;
@Inject
private GpuDeviceDao gpuDeviceDao;
public GpuCardDaoImpl() {
allFieldSearch = createSearchBuilder();
allFieldSearch.and("name", allFieldSearch.entity().getName(), SearchCriteria.Op.EQ);
allFieldSearch.and("vendorId", allFieldSearch.entity().getVendorId(), SearchCriteria.Op.EQ);
allFieldSearch.and("vendorName", allFieldSearch.entity().getVendorName(), SearchCriteria.Op.EQ);
allFieldSearch.and("deviceId", allFieldSearch.entity().getDeviceId(), SearchCriteria.Op.EQ);
allFieldSearch.and("deviceName", allFieldSearch.entity().getDeviceName(), SearchCriteria.Op.EQ);
allFieldSearch.done();
}
@Override
public GpuCardVO findByVendorIdAndDeviceId(String vendorId, String deviceId) {
SearchCriteria<GpuCardVO> sc = allFieldSearch.create();
sc.setParameters("vendorId", vendorId);
sc.setParameters("deviceId", deviceId);
return findOneBy(sc);
}
@Override
public Pair<List<GpuCardVO>, Integer> searchAndCountGpuCards(Long id, String keyword, String vendorId,
String vendorName, String deviceId, String deviceName, boolean activeOnly, Long startIndex, Long pageSize
) {
Filter searchFilter = new Filter(GpuCardVO.class, "id", true, startIndex, pageSize);
SearchBuilder<GpuCardVO> sb = createSearchBuilder();
if (id != null) {
sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
}
if (keyword != null) {
sb.op("nameKeyword", sb.entity().getName(), SearchCriteria.Op.LIKE);
sb.and("deviceNameKeyword", sb.entity().getDeviceName(), SearchCriteria.Op.LIKE);
sb.and("vendorNameKeyword", sb.entity().getVendorName(), SearchCriteria.Op.LIKE);
sb.cp();
}
if (vendorId != null) {
sb.and("vendorId", sb.entity().getVendorId(), SearchCriteria.Op.EQ);
}
if (vendorName != null) {
sb.and("vendorName", sb.entity().getVendorName(), SearchCriteria.Op.EQ);
}
if (deviceId != null) {
sb.and("deviceId", sb.entity().getDeviceId(), SearchCriteria.Op.EQ);
}
if (deviceName != null) {
sb.and("deviceName", sb.entity().getDeviceName(), SearchCriteria.Op.EQ);
}
if (activeOnly) {
sb.and("ids", sb.entity().getId(), SearchCriteria.Op.IN);
}
sb.done();
// Build search criteria
SearchCriteria<GpuCardVO> sc = sb.create();
if (id != null) {
sc.setParameters("id", id);
}
if (keyword != null) {
sc.setParameters("nameKeyword", "%" + keyword + "%");
sc.setParameters("deviceNameKeyword", "%" + keyword + "%");
sc.setParameters("vendorNameKeyword", "%" + keyword + "%");
}
if (vendorId != null) {
sc.setParameters("vendorId", vendorId);
}
if (vendorName != null) {
sc.setParameters("vendorName", vendorName);
}
if (deviceId != null) {
sc.setParameters("deviceId", deviceId);
}
if (deviceName != null) {
sc.setParameters("deviceName", deviceName);
}
if (activeOnly) {
List<Long> cardIds = gpuDeviceDao.getDistinctGpuCardIds();
if (cardIds.isEmpty()) {
return new Pair<>(List.of(), 0);
}
sc.setParameters("ids", cardIds.toArray());
}
return searchAndCount(sc, searchFilter);
}
}

View File

@ -0,0 +1,71 @@
// 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 com.cloud.gpu.dao;
import com.cloud.gpu.GpuDeviceVO;
import com.cloud.utils.Pair;
import com.cloud.utils.db.GenericDao;
import java.util.List;
public interface GpuDeviceDao extends GenericDao<GpuDeviceVO, Long> {
List<GpuDeviceVO> listByIds(List<Long> ids);
/**
* Find GPU device by host ID and bus address
*
* @param hostId the host ID
* @param busAddress the PCI bus address
* @return GpuDeviceVO
*/
GpuDeviceVO findByHostIdAndBusAddress(long hostId, String busAddress);
/**
* List GPU devices by host ID
*
* @param hostId the ID of the host
* @return a list of GPU devices for the host
*/
List<GpuDeviceVO> listByHostId(long hostId);
/**
* List GPU devices by VM ID
*
* @param vmId the VM ID
* @return list of GpuDeviceVO
*/
List<GpuDeviceVO> listByVmId(long vmId);
boolean isVgpuProfileInUse(long vgpuProfileId);
boolean isGpuCardInUse(long cardId);
List<GpuDeviceVO> listByHostAndVm(Long hostId, long vmId);
List<GpuDeviceVO> listDevicesForAllocation(Long hostId, Long vgpuProfileId);
Pair<List<GpuDeviceVO>, Integer> searchAndCountGpuDevices(
Long id, String keyword, Long hostId, Long vmId, Long gpuCardId, Long vgpuProfileId,
Long startIndex, Long pageSize);
List<Long> getDistinctGpuCardIds();
List<Long> getDistinctVgpuProfileIds();
List<GpuDeviceVO> listByParentGpuDeviceId(Long parentGpuDeviceId);
}

View File

@ -0,0 +1,260 @@
// 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 com.cloud.gpu.dao;
import com.cloud.gpu.GpuCardVO;
import com.cloud.gpu.GpuDeviceVO;
import com.cloud.gpu.VgpuProfileVO;
import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.JoinBuilder;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import org.apache.cloudstack.gpu.GpuDevice;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
public class GpuDeviceDaoImpl extends GenericDaoBase<GpuDeviceVO, Long> implements GpuDeviceDao {
private static final String IDS = "ids";
private static final String HOST_ID = "hostId";
private static final String VM_ID = "vmId";
private static final String BUS_ADDRESS = "busAddress";
private static final String CARD_ID = "cardId";
private static final String VGPU_PROFILE_ID = "vgpuProfileId";
private static final String PARENT_GPU_DEVICE_ID = "parentGpuDeviceId";
private static final String STATE = "state";
private static final String MANAGED_STATE = "managedState";
private static final String TYPE = "type";
private final SearchBuilder<GpuDeviceVO> allFieldSearch;
private SearchBuilder<GpuDeviceVO> devicesForAllocationSearch;
@Inject
private GpuCardDao gpuCardDao;
@Inject
private VgpuProfileDao vgpuProfileDao;
public GpuDeviceDaoImpl() {
allFieldSearch = createSearchBuilder();
allFieldSearch.and(IDS, allFieldSearch.entity().getId(), SearchCriteria.Op.IN);
allFieldSearch.and(HOST_ID, allFieldSearch.entity().getHostId(), SearchCriteria.Op.EQ);
allFieldSearch.and(CARD_ID, allFieldSearch.entity().getCardId(), SearchCriteria.Op.EQ);
allFieldSearch.and(BUS_ADDRESS, allFieldSearch.entity().getBusAddress(), SearchCriteria.Op.EQ);
allFieldSearch.and(STATE, allFieldSearch.entity().getState(), SearchCriteria.Op.EQ);
allFieldSearch.and(VGPU_PROFILE_ID, allFieldSearch.entity().getVgpuProfileId(), SearchCriteria.Op.EQ);
allFieldSearch.and(PARENT_GPU_DEVICE_ID, allFieldSearch.entity().getParentGpuDeviceId(), SearchCriteria.Op.EQ);
allFieldSearch.and(VM_ID, allFieldSearch.entity().getVmId(), SearchCriteria.Op.EQ);
allFieldSearch.done();
devicesForAllocationSearch = createSearchBuilder();
devicesForAllocationSearch.and(HOST_ID, devicesForAllocationSearch.entity().getHostId(), SearchCriteria.Op.EQ);
devicesForAllocationSearch.and(VGPU_PROFILE_ID, devicesForAllocationSearch.entity().getVgpuProfileId(), SearchCriteria.Op.IN);
devicesForAllocationSearch.and(STATE, devicesForAllocationSearch.entity().getState(), SearchCriteria.Op.EQ);
devicesForAllocationSearch.and(MANAGED_STATE, devicesForAllocationSearch.entity().getManagedState(), SearchCriteria.Op.EQ);
devicesForAllocationSearch.and(TYPE, devicesForAllocationSearch.entity().getType(), SearchCriteria.Op.NEQ);
devicesForAllocationSearch.done();
}
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
return super.configure(name, params);
}
@Override
public List<GpuDeviceVO> listByIds(List<Long> ids) {
if (CollectionUtils.isEmpty(ids)) {
return Collections.emptyList();
}
SearchCriteria<GpuDeviceVO> sc = allFieldSearch.create();
sc.setParameters(IDS, ids.toArray());
return listBy(sc);
}
@Override
public GpuDeviceVO findByHostIdAndBusAddress(long hostId, String busAddress) {
SearchCriteria<GpuDeviceVO> sc = allFieldSearch.create();
sc.setParameters(HOST_ID, hostId);
sc.setParameters(BUS_ADDRESS, busAddress);
return findOneBy(sc);
}
@Override
public List<GpuDeviceVO> listByHostId(long hostId) {
SearchCriteria<GpuDeviceVO> sc = allFieldSearch.create();
sc.setParameters(HOST_ID, hostId);
return listBy(sc);
}
@Override
public List<GpuDeviceVO> listByVmId(long vmId) {
SearchCriteria<GpuDeviceVO> sc = allFieldSearch.create();
sc.setParameters(VM_ID, vmId);
return listBy(sc);
}
@Override
public boolean isVgpuProfileInUse(long vgpuProfileId) {
SearchCriteria<GpuDeviceVO> sc = allFieldSearch.create();
sc.setParameters(VGPU_PROFILE_ID, vgpuProfileId);
return getCount(sc) > 0;
}
@Override
public boolean isGpuCardInUse(long cardId) {
SearchCriteria<GpuDeviceVO> sc = allFieldSearch.create();
sc.setParameters(CARD_ID, cardId);
return getCount(sc) > 0;
}
@Override
public List<GpuDeviceVO> listByHostAndVm(Long hostId, long vmId) {
SearchCriteria<GpuDeviceVO> sc = allFieldSearch.create();
sc.setParameters(HOST_ID, hostId);
sc.setParameters(VM_ID, vmId);
return search(sc, null);
}
@Override
public List<GpuDeviceVO> listDevicesForAllocation(Long hostId, Long vgpuProfileId) {
SearchCriteria<GpuDeviceVO> sc = devicesForAllocationSearch.create();
sc.setParameters(HOST_ID, hostId);
sc.setParameters(VGPU_PROFILE_ID, vgpuProfileId);
sc.setParameters(STATE, GpuDevice.State.Free);
sc.setParameters(MANAGED_STATE, GpuDevice.ManagedState.Managed);
sc.setParameters(TYPE, GpuDevice.DeviceType.VGPUOnly);
return search(sc, null);
}
@Override
public Pair<List<GpuDeviceVO>, Integer> searchAndCountGpuDevices(Long id, String keyword, Long hostId, Long vmId,
Long gpuCardId, Long vgpuProfileId, Long startIndex, Long pageSize) {
Filter searchFilter = new Filter(GpuDeviceVO.class, "id", true, startIndex, pageSize);
SearchBuilder<GpuDeviceVO> sb = createSearchBuilder();
if (id != null) {
sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
}
if (hostId != null) {
sb.and("hostId", sb.entity().getHostId(), SearchCriteria.Op.EQ);
}
if (vmId != null) {
sb.and("vmId", sb.entity().getVmId(), SearchCriteria.Op.EQ);
}
if (gpuCardId != null) {
sb.and("cardId", sb.entity().getCardId(), SearchCriteria.Op.EQ);
}
if (vgpuProfileId != null) {
sb.and("vgpuProfileId", sb.entity().getVgpuProfileId(), SearchCriteria.Op.EQ);
}
if (keyword != null) {
SearchBuilder<GpuCardVO> cardSb = gpuCardDao.createSearchBuilder();
SearchBuilder<VgpuProfileVO> profileSb = vgpuProfileDao.createSearchBuilder();
sb.join("cardJoin", cardSb, sb.entity().getCardId(), cardSb.entity().getId(), JoinBuilder.JoinType.INNER);
sb.join("profileJoin", profileSb, sb.entity().getCardId(), profileSb.entity().getId(),
JoinBuilder.JoinType.INNER);
sb.op("cardNameKeyword", cardSb.entity().getName(), SearchCriteria.Op.LIKE);
sb.or("cardNameKeyword", cardSb.entity().getVendorName(), SearchCriteria.Op.LIKE);
sb.or("cardNameKeyword", cardSb.entity().getDeviceName(), SearchCriteria.Op.LIKE);
sb.op("profileNameKeyword", profileSb.entity().getName(), SearchCriteria.Op.LIKE);
sb.op("profileDescriptionKeyword", profileSb.entity().getDescription(), SearchCriteria.Op.LIKE);
sb.cp();
}
sb.done();
// Build search criteria
SearchCriteria<GpuDeviceVO> sc = sb.create();
if (id != null) {
sc.setParameters("id", id);
}
if (hostId != null) {
sc.setParameters("hostId", hostId);
}
if (vmId != null) {
sc.setParameters("vmId", vmId);
}
if (gpuCardId != null) {
sc.setParameters("cardId", gpuCardId);
}
if (vgpuProfileId != null) {
sc.setParameters("vgpuProfileId", vgpuProfileId);
}
if (keyword != null) {
sc.setJoinParameters("cardJoin", "cardNameKeyword", "%" + keyword + "%");
sc.setJoinParameters("cardJoin", "cardNameKeyword", "%" + keyword + "%");
sc.setJoinParameters("cardJoin", "cardNameKeyword", "%" + keyword + "%");
sc.setJoinParameters("profileJoin", "profileNameKeyword", "%" + keyword + "%");
sc.setJoinParameters("profileJoin", "profileDescriptionKeyword", "%" + keyword + "%");
}
return searchAndCount(sc, searchFilter);
}
@Override
public List<Long> getDistinctGpuCardIds() {
SearchBuilder<GpuDeviceVO> sb = createSearchBuilder();
sb.select(null, SearchCriteria.Func.DISTINCT, sb.entity().getCardId());
sb.done();
SearchCriteria<GpuDeviceVO> sc = sb.create();
List<GpuDeviceVO> gpuDevices = listBy(sc);
if (CollectionUtils.isEmpty(gpuDevices)) {
return Collections.emptyList();
}
return gpuDevices.stream()
.map(GpuDeviceVO::getCardId)
.distinct()
.collect(Collectors.toList());
}
@Override
public List<Long> getDistinctVgpuProfileIds() {
SearchBuilder<GpuDeviceVO> sb = createSearchBuilder();
sb.select(null, SearchCriteria.Func.DISTINCT, sb.entity().getVgpuProfileId());
sb.done();
SearchCriteria<GpuDeviceVO> sc = sb.create();
List<GpuDeviceVO> gpuDevices = listBy(sc);
if (CollectionUtils.isEmpty(gpuDevices)) {
return Collections.emptyList();
}
return gpuDevices.stream()
.map(GpuDeviceVO::getVgpuProfileId)
.distinct()
.collect(Collectors.toList());
}
@Override
public List<GpuDeviceVO> listByParentGpuDeviceId(Long parentGpuDeviceId) {
SearchCriteria<GpuDeviceVO> sc = allFieldSearch.create();
sc.setParameters(PARENT_GPU_DEVICE_ID, parentGpuDeviceId);
return listBy(sc);
}
}

View File

@ -19,6 +19,7 @@ package com.cloud.gpu.dao;
import java.util.List;
import com.cloud.gpu.HostGpuGroupsVO;
import com.cloud.utils.Pair;
import com.cloud.utils.db.GenericDao;
public interface HostGpuGroupsDao extends GenericDao<HostGpuGroupsVO, Long> {
@ -57,4 +58,15 @@ public interface HostGpuGroupsDao extends GenericDao<HostGpuGroupsVO, Long> {
*/
void persist(long hostId, List<String> gpuGroups);
/**
* Returns max and remaining GPU capacity
*
* @param dcId
* @param podId
* @param clusterId
* @param hostId
* @return Pair containing max GPU capacity and remaining GPU capacity
*/
Pair<Long, Long> getGpuStats(Long dcId, Long podId, Long clusterId, Long hostId);
}

View File

@ -16,9 +16,16 @@
// under the License.
package com.cloud.gpu.dao;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.cloud.utils.Pair;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.exception.CloudRuntimeException;
import org.springframework.stereotype.Component;
import com.cloud.gpu.HostGpuGroupsVO;
@ -87,4 +94,75 @@ public class HostGpuGroupsDaoImpl extends GenericDaoBase<HostGpuGroupsVO, Long>
sc.setParameters("hostId", hostId);
remove(sc);
}
@Override
public Pair<Long, Long> getGpuStats(Long dcId, Long podId, Long clusterId, Long hostId) {
TransactionLegacy txn = TransactionLegacy.currentTxn();
Pair<Long, Long> result = null;
List<Long> resourceIdList = new ArrayList<>();
String query = getStatsQuery(resourceIdList, dcId, podId, clusterId, hostId);
try {
PreparedStatement pstmt = txn.prepareAutoCloseStatement(query);
for (int i = 0; i < resourceIdList.size(); i++) {
pstmt.setLong(1 + i, resourceIdList.get(i));
}
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
result = new Pair<>(rs.getLong(1), rs.getLong(2));
}
return result;
} catch (SQLException e) {
throw new CloudRuntimeException("Error while fetching GPU stats: " + e.getMessage(), e);
} catch (Throwable e) {
throw new CloudRuntimeException("Caught: " + query, e);
}
}
private String getStatsQuery(List<Long> resourceIdList, Long dcId, Long podId, Long clusterId, Long hostId) {
StringBuilder query = new StringBuilder("SELECT SUM(max_capacity), SUM(remaining_capacity)" +
"FROM vgpu_types " +
"WHERE" +
" gpu_group_id IN (" +
" SELECT" +
" host_gpu_groups.id" +
" FROM" +
" host_gpu_groups" +
" INNER JOIN host ON host.id = host_gpu_groups.host_id ");
if (dcId != null) {
query.append("WHERE host.data_center_id = ? ");
resourceIdList.add(dcId);
}
if (podId != null) {
if (resourceIdList.isEmpty()) {
query.append("WHERE ");
} else {
query.append("AND ");
}
query.append(" host.pod_id = ? ");
resourceIdList.add(podId);
}
if (clusterId != null) {
if (resourceIdList.isEmpty()) {
query.append("WHERE ");
} else {
query.append("AND ");
}
query.append(" host.cluster_id = ? ");
resourceIdList.add(clusterId);
}
if (hostId != null) {
if (resourceIdList.isEmpty()) {
query.append("WHERE ");
} else {
query.append("AND ");
}
query.append(" host.id = ? ");
resourceIdList.add(hostId);
}
query.append(" )");
return query.toString();
}
}

View File

@ -16,6 +16,17 @@
//under the License.
package com.cloud.gpu.dao;
import com.cloud.agent.api.VgpuTypesInfo;
import com.cloud.gpu.HostGpuGroupsVO;
import com.cloud.gpu.VGPUTypesVO;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.exception.CloudRuntimeException;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@ -25,42 +36,30 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import javax.inject.Inject;
import org.springframework.stereotype.Component;
import com.cloud.agent.api.VgpuTypesInfo;
import com.cloud.gpu.HostGpuGroupsVO;
import com.cloud.gpu.VGPUTypesVO;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.exception.CloudRuntimeException;
@Component
public class VGPUTypesDaoImpl extends GenericDaoBase<VGPUTypesVO, Long> implements VGPUTypesDao {
private final SearchBuilder<VGPUTypesVO> _searchByGroupId;
private final SearchBuilder<VGPUTypesVO> _searchByGroupIdVGPUType;
@Inject protected HostGpuGroupsDao _hostGpuGroupsDao;
@Inject
protected HostGpuGroupsDao hostGpuGroupsDao;
private static final String LIST_ZONE_POD_CLUSTER_WIDE_GPU_CAPACITIES =
"SELECT host_gpu_groups.group_name, vgpu_type, max_vgpu_per_pgpu, SUM(remaining_capacity) AS remaining_capacity, SUM(max_capacity) AS total_capacity FROM" +
" `cloud`.`vgpu_types` INNER JOIN `cloud`.`host_gpu_groups` ON vgpu_types.gpu_group_id = host_gpu_groups.id INNER JOIN `cloud`.`host`" +
" ON host_gpu_groups.host_id = host.id WHERE host.type = 'Routing' AND host.data_center_id = ?";
" `cloud`.`vgpu_types` INNER JOIN `cloud`.`host_gpu_groups` ON vgpu_types.gpu_group_id = host_gpu_groups.id INNER JOIN `cloud`.`host`" +
" ON host_gpu_groups.host_id = host.id WHERE host.type = 'Routing' AND vgpu_types.max_capacity > 0 AND host.data_center_id = ?";
private final SearchBuilder<VGPUTypesVO> searchByGroupId;
private final SearchBuilder<VGPUTypesVO> searchByGroupIdVGPUType;
public VGPUTypesDaoImpl() {
_searchByGroupId = createSearchBuilder();
_searchByGroupId.and("groupId", _searchByGroupId.entity().getGpuGroupId(), SearchCriteria.Op.EQ);
_searchByGroupId.done();
searchByGroupId = createSearchBuilder();
searchByGroupId.and("groupId", searchByGroupId.entity().getGpuGroupId(), SearchCriteria.Op.EQ);
searchByGroupId.done();
_searchByGroupIdVGPUType = createSearchBuilder();
_searchByGroupIdVGPUType.and("groupId", _searchByGroupIdVGPUType.entity().getGpuGroupId(), SearchCriteria.Op.EQ);
_searchByGroupIdVGPUType.and("vgpuType", _searchByGroupIdVGPUType.entity().getVgpuType(), SearchCriteria.Op.EQ);
_searchByGroupIdVGPUType.done();
searchByGroupIdVGPUType = createSearchBuilder();
searchByGroupIdVGPUType.and("groupId", searchByGroupIdVGPUType.entity().getGpuGroupId(), SearchCriteria.Op.EQ);
searchByGroupIdVGPUType.and("vgpuType", searchByGroupIdVGPUType.entity().getVgpuType(), SearchCriteria.Op.EQ);
searchByGroupIdVGPUType.done();
}
@Override
@ -83,7 +82,7 @@ public class VGPUTypesDaoImpl extends GenericDaoBase<VGPUTypesVO, Long> implemen
finalQuery.append(" AND host.cluster_id = ?");
resourceIdList.add(clusterId);
}
finalQuery.append(" GROUP BY host_gpu_groups.group_name, vgpu_type");
finalQuery.append(" GROUP BY host_gpu_groups.group_name, vgpu_type, max_vgpu_per_pgpu");
try {
pstmt = txn.prepareAutoCloseStatement(finalQuery.toString());
@ -106,14 +105,14 @@ public class VGPUTypesDaoImpl extends GenericDaoBase<VGPUTypesVO, Long> implemen
@Override
public List<VGPUTypesVO> listByGroupId(long groupId) {
SearchCriteria<VGPUTypesVO> sc = _searchByGroupId.create();
SearchCriteria<VGPUTypesVO> sc = searchByGroupId.create();
sc.setParameters("groupId", groupId);
return listBy(sc);
}
@Override
public VGPUTypesVO findByGroupIdVGPUType(long groupId, String vgpuType) {
SearchCriteria<VGPUTypesVO> sc = _searchByGroupIdVGPUType.create();
SearchCriteria<VGPUTypesVO> sc = searchByGroupIdVGPUType.create();
sc.setParameters("groupId", groupId);
sc.setParameters("vgpuType", vgpuType);
return findOneBy(sc);
@ -124,7 +123,7 @@ public class VGPUTypesDaoImpl extends GenericDaoBase<VGPUTypesVO, Long> implemen
Iterator<Entry<String, HashMap<String, VgpuTypesInfo>>> it1 = groupDetails.entrySet().iterator();
while (it1.hasNext()) {
Entry<String, HashMap<String, VgpuTypesInfo>> entry = it1.next();
HostGpuGroupsVO gpuGroup = _hostGpuGroupsDao.findByHostIdGroupName(hostId, entry.getKey());
HostGpuGroupsVO gpuGroup = hostGpuGroupsDao.findByHostIdGroupName(hostId, entry.getKey());
HashMap<String, VgpuTypesInfo> values = entry.getValue();
Iterator<Entry<String, VgpuTypesInfo>> it2 = values.entrySet().iterator();
while (it2.hasNext()) {

View File

@ -0,0 +1,33 @@
// 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 com.cloud.gpu.dao;
import com.cloud.gpu.VgpuProfileVO;
import com.cloud.utils.Pair;
import com.cloud.utils.db.GenericDao;
import java.util.List;
public interface VgpuProfileDao extends GenericDao<VgpuProfileVO, Long> {
VgpuProfileVO findByNameAndCardId(String name, long cardId);
int removeByCardId(long cardId);
Pair<List<VgpuProfileVO>, Integer> searchAndCountVgpuProfiles(Long id, String name, String keyword, Long gpuCardId,
boolean activeOnly, Long startIndex, Long pageSize);
}

View File

@ -0,0 +1,110 @@
// 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 com.cloud.gpu.dao;
import com.cloud.gpu.VgpuProfileVO;
import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
import java.util.List;
@Component
public class VgpuProfileDaoImpl extends GenericDaoBase<VgpuProfileVO, Long> implements VgpuProfileDao {
private final SearchBuilder<VgpuProfileVO> allFieldSearch;
@Inject
private GpuDeviceDao gpuDeviceDao;
public VgpuProfileDaoImpl() {
allFieldSearch = createSearchBuilder();
allFieldSearch.and("name", allFieldSearch.entity().getName(), SearchCriteria.Op.EQ);
allFieldSearch.and("cardId", allFieldSearch.entity().getCardId(), SearchCriteria.Op.IN);
allFieldSearch.done();
}
@Override
public VgpuProfileVO findByNameAndCardId(String name, long cardId) {
SearchCriteria<VgpuProfileVO> sc = allFieldSearch.create();
sc.setParameters("name", name);
sc.setParameters("cardId", cardId);
return findOneBy(sc);
}
@Override
public int removeByCardId(long cardId) {
SearchCriteria<VgpuProfileVO> sc = allFieldSearch.create();
sc.setParameters("cardId", cardId);
return remove(sc);
}
@Override
public Pair<List<VgpuProfileVO>, Integer> searchAndCountVgpuProfiles(Long id, String name, String keyword,
Long gpuCardId, boolean activeOnly, Long startIndex, Long pageSize) {
Filter searchFilter = new Filter(VgpuProfileVO.class, "id", true, startIndex, pageSize);
SearchBuilder<VgpuProfileVO> sb = createSearchBuilder();
if (id != null) {
sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
}
if (name != null) {
sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ);
}
if (keyword != null) {
sb.and("keywordName", sb.entity().getName(), SearchCriteria.Op.LIKE);
sb.and("keywordDescription", sb.entity().getDescription(), SearchCriteria.Op.LIKE);
}
if (gpuCardId != null) {
sb.and("cardId", sb.entity().getCardId(), SearchCriteria.Op.EQ);
}
if (activeOnly) {
sb.and("ids", sb.entity().getId(), SearchCriteria.Op.IN);
}
sb.done();
// Build search criteria
SearchCriteria<VgpuProfileVO> sc = sb.create();
if (id != null) {
sc.setParameters("id", id);
}
if (name != null) {
sc.setParameters("name", name);
}
if (keyword != null) {
sc.setParameters("keywordName", "%" + keyword + "%");
sc.setParameters("keywordDescription", "%" + keyword + "%");
}
if (gpuCardId != null) {
sc.setParameters("cardId", gpuCardId);
}
if (activeOnly) {
List<Long> vgpuProfileIds = gpuDeviceDao.getDistinctVgpuProfileIds();
if (vgpuProfileIds.isEmpty()) {
return new Pair<>(List.of(), 0);
}
sc.setParameters("ids", vgpuProfileIds.toArray());
}
return searchAndCount(sc, searchFilter);
}
}

View File

@ -124,6 +124,15 @@ public class ServiceOfferingVO implements ServiceOffering {
@Column(name = "dynamic_scaling_enabled")
private boolean dynamicScalingEnabled = true;
@Column(name = "vgpu_profile_id")
private Long vgpuProfileId;
@Column(name = "gpu_count")
private Integer gpuCount;
@Column(name = "gpu_display")
private Boolean gpuDisplay;
// This is a delayed load value. If the value is null,
// then this field has not been loaded yet.
// Call service offering dao to load it.
@ -198,6 +207,8 @@ public class ServiceOfferingVO implements ServiceOffering {
systemUse = offering.isSystemUse();
dynamicScalingEnabled = offering.isDynamicScalingEnabled();
diskOfferingStrictness = offering.diskOfferingStrictness;
vgpuProfileId = offering.vgpuProfileId;
gpuCount = offering.gpuCount;
}
@Override
@ -445,4 +456,30 @@ public class ServiceOfferingVO implements ServiceOffering {
public void setDiskOfferingStrictness(boolean diskOfferingStrictness) {
this.diskOfferingStrictness = diskOfferingStrictness;
}
@Override
public Long getVgpuProfileId() {
return vgpuProfileId;
}
public void setVgpuProfileId(Long vgpuProfileId) {
this.vgpuProfileId = vgpuProfileId;
}
@Override
public Integer getGpuCount() {
return gpuCount;
}
public void setGpuCount(Integer gpuCount) {
this.gpuCount = gpuCount;
}
public Boolean getGpuDisplay() {
return gpuDisplay;
}
public void setGpuDisplay(Boolean gpuDisplay) {
this.gpuDisplay = gpuDisplay;
}
}

View File

@ -22,6 +22,7 @@ import java.util.Map;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.storage.Storage.ProvisioningType;
import com.cloud.utils.db.GenericDao;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.vm.VirtualMachine;
/*
@ -57,4 +58,6 @@ public interface ServiceOfferingDao extends GenericDao<ServiceOfferingVO, Long>
ServiceOfferingVO findServiceOfferingByComputeOnlyDiskOffering(long diskOfferingId, boolean includingRemoved);
List<Long> listIdsByHostTag(String tag);
void addCheckForGpuEnabled(SearchBuilder<ServiceOfferingVO> serviceOfferingSearch, Boolean gpuEnabled);
}

View File

@ -312,4 +312,13 @@ public class ServiceOfferingDaoImpl extends GenericDaoBase<ServiceOfferingVO, Lo
sc.setParameters("tagEndLike", "%," + tag);
return customSearch(sc, null);
}
@Override
public void addCheckForGpuEnabled(SearchBuilder<ServiceOfferingVO> serviceOfferingSearch, Boolean gpuEnabled) {
if (gpuEnabled) {
serviceOfferingSearch.and("gpuEnabled", serviceOfferingSearch.entity().getVgpuProfileId(), SearchCriteria.Op.NNULL);
} else {
serviceOfferingSearch.and("gpuDisabled", serviceOfferingSearch.entity().getVgpuProfileId(), SearchCriteria.Op.NULL);
}
}
}

View File

@ -821,6 +821,7 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
reservationDao.setResourceId(Resource.ResourceType.user_vm, userVM.getId());
reservationDao.setResourceId(Resource.ResourceType.cpu, userVM.getId());
reservationDao.setResourceId(Resource.ResourceType.memory, userVM.getId());
reservationDao.setResourceId(Resource.ResourceType.gpu, userVM.getId());
return userVM;
});
}

View File

@ -131,12 +131,22 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem
private static final String ORDER_HOSTS_NUMBER_OF_VMS_FOR_ACCOUNT_PART2 = " GROUP BY host.id ORDER BY 2 ASC ";
private static final String COUNT_VMS_BASED_ON_VGPU_TYPES1 =
private static final String COUNT_VMS_BASED_ON_VGPU_TYPES1_LEGACY =
"SELECT pci, type, SUM(vmcount) FROM (SELECT MAX(IF(offering.name = 'pciDevice',value,'')) AS pci, MAX(IF(offering.name = 'vgpuType', value,'')) " +
"AS type, COUNT(DISTINCT vm.id) AS vmcount FROM service_offering_details offering INNER JOIN vm_instance vm ON offering.service_offering_id = vm.service_offering_id " +
"INNER JOIN `cloud`.`host` ON vm.host_id = host.id WHERE vm.state = 'Running' AND host.data_center_id = ? ";
private static final String COUNT_VMS_BASED_ON_VGPU_TYPES2_LEGACY =
"GROUP BY vm.service_offering_id) results GROUP BY pci, type";
private static final String COUNT_VMS_BASED_ON_VGPU_TYPES1 =
"SELECT CONCAT(gpu_card.vendor_name, ' ', gpu_card.device_name), vgpu_profile.name, COUNT(gpu_device.vm_id) "
+ "FROM `cloud`.`gpu_device` "
+ "INNER JOIN `cloud`.`host` ON gpu_device.host_id = host.id "
+ "INNER JOIN `cloud`.`gpu_card` ON gpu_device.card_id = gpu_card.id "
+ "INNER JOIN `cloud`.`vgpu_profile` ON vgpu_profile.id = gpu_device.vgpu_profile_id "
+ "WHERE vm_id IS NOT NULL AND host.data_center_id = ? ";
private static final String COUNT_VMS_BASED_ON_VGPU_TYPES2 =
"GROUP BY offering.service_offering_id) results GROUP BY pci, type";
"GROUP BY gpu_card.name, vgpu_profile.name";
private static final String UPDATE_SYSTEM_VM_TEMPLATE_ID_FOR_HYPERVISOR = "UPDATE `cloud`.`vm_instance` SET vm_template_id = ? WHERE type <> 'User' AND hypervisor_type = ? AND removed is NULL";
@ -794,40 +804,52 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem
@Override
public HashMap<String, Long> countVgpuVMs(Long dcId, Long podId, Long clusterId) {
StringBuilder finalQueryLegacy = new StringBuilder();
StringBuilder finalQuery = new StringBuilder();
TransactionLegacy txn = TransactionLegacy.currentTxn();
PreparedStatement pstmtLegacy = null;
PreparedStatement pstmt = null;
List<Long> resourceIdList = new ArrayList<Long>();
HashMap<String, Long> result = new HashMap<String, Long>();
resourceIdList.add(dcId);
finalQueryLegacy.append(COUNT_VMS_BASED_ON_VGPU_TYPES1_LEGACY);
finalQuery.append(COUNT_VMS_BASED_ON_VGPU_TYPES1);
if (podId != null) {
finalQueryLegacy.append("AND host.pod_id = ? ");
finalQuery.append("AND host.pod_id = ? ");
resourceIdList.add(podId);
}
if (clusterId != null) {
finalQueryLegacy.append("AND host.cluster_id = ? ");
finalQuery.append("AND host.cluster_id = ? ");
resourceIdList.add(clusterId);
}
finalQueryLegacy.append(COUNT_VMS_BASED_ON_VGPU_TYPES2_LEGACY);
finalQuery.append(COUNT_VMS_BASED_ON_VGPU_TYPES2);
try {
pstmtLegacy = txn.prepareAutoCloseStatement(finalQueryLegacy.toString());
pstmt = txn.prepareAutoCloseStatement(finalQuery.toString());
for (int i = 0; i < resourceIdList.size(); i++) {
pstmtLegacy.setLong(1 + i, resourceIdList.get(i));
pstmt.setLong(1 + i, resourceIdList.get(i));
}
ResultSet rs = pstmt.executeQuery();
ResultSet rs = pstmtLegacy.executeQuery();
while (rs.next()) {
result.put(rs.getString(1).concat(rs.getString(2)), rs.getLong(3));
}
rs = pstmt.executeQuery();
while (rs.next()) {
result.put(rs.getString(1).concat(rs.getString(2)), rs.getLong(3));
}
return result;
} catch (SQLException e) {
throw new CloudRuntimeException("DB Exception on: " + finalQuery, e);
throw new CloudRuntimeException("DB Exception on: " + finalQueryLegacy, e);
} catch (Throwable e) {
throw new CloudRuntimeException("Caught: " + finalQuery, e);
throw new CloudRuntimeException("Caught: " + finalQueryLegacy, e);
}
}

View File

@ -305,4 +305,7 @@
<bean id="guiThemeDaoImpl" class="org.apache.cloudstack.gui.theme.dao.GuiThemeDaoImpl" />
<bean id="guiThemeDetailsDaoImpl" class="org.apache.cloudstack.gui.theme.dao.GuiThemeDetailsDaoImpl" />
<bean id="guiThemeJoinDaoImpl" class="org.apache.cloudstack.gui.theme.dao.GuiThemeJoinDaoImpl" />
<bean id="gpuCardDaoImpl" class="com.cloud.gpu.dao.GpuCardDaoImpl" />
<bean id="gpuDeviceDaoImpl" class="com.cloud.gpu.dao.GpuDeviceDaoImpl" />
<bean id="vgpuProfileDaoImpl" class="com.cloud.gpu.dao.VgpuProfileDaoImpl" />
</beans>

View File

@ -238,6 +238,68 @@ CREATE TABLE IF NOT EXISTS `cloud`.`gui_themes_details` (
CONSTRAINT `fk_gui_themes_details__gui_theme_id` FOREIGN KEY (`gui_theme_id`) REFERENCES `gui_themes`(`id`)
);
-- Create the GPU card table to hold the GPU card information
CREATE TABLE IF NOT EXISTS `cloud`.`gpu_card` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`uuid` varchar(40) NOT NULL UNIQUE,
`device_id` varchar(4) NOT NULL COMMENT 'device id of the GPU card',
`device_name` varchar(255) NOT NULL COMMENT 'device name of the GPU card',
`name` varchar(255) NOT NULL COMMENT 'name of the GPU card',
`vendor_name` varchar(255) NOT NULL COMMENT 'vendor name of the GPU card',
`vendor_id` varchar(4) NOT NULL COMMENT 'vendor id of the GPU card',
`created` datetime NOT NULL COMMENT 'date created',
PRIMARY KEY (`id`),
UNIQUE KEY (`vendor_id`, `device_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='GPU cards supported by CloudStack';
-- Create the vGPU profile table to hold the vGPU profile information.
CREATE TABLE IF NOT EXISTS `cloud`.`vgpu_profile` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`uuid` varchar(40) NOT NULL UNIQUE,
`name` varchar(255) NOT NULL COMMENT 'name of the vGPU profile',
`description` varchar(255) DEFAULT NULL COMMENT 'description of the vGPU profile',
`card_id` bigint unsigned NOT NULL COMMENT 'id of the GPU card',
`video_ram` bigint unsigned DEFAULT NULL COMMENT 'video RAM of the vGPU profile',
`max_heads` bigint unsigned DEFAULT NULL COMMENT 'maximum number of heads of the vGPU profile',
`max_resolution_x` bigint unsigned DEFAULT NULL COMMENT 'maximum resolution x of the vGPU profile',
`max_resolution_y` bigint unsigned DEFAULT NULL COMMENT 'maximum resolution y of the vGPU profile',
`max_vgpu_per_pgpu` bigint unsigned DEFAULT NULL COMMENT 'Maximum number of vGPUs per physical GPU',
`created` datetime NOT NULL COMMENT 'date created',
PRIMARY KEY (`id`),
UNIQUE KEY (`name`, `card_id`),
CONSTRAINT `fk_vgpu_profile_card_id` FOREIGN KEY (`card_id`) REFERENCES `gpu_card`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='vGPU profiles supported by CloudStack';
-- Create the GPU device table to hold the GPU device information on different hosts
CREATE TABLE IF NOT EXISTS `cloud`.`gpu_device` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`uuid` varchar(40) NOT NULL UNIQUE,
`card_id` bigint unsigned NOT NULL COMMENT 'id of the GPU card',
`vgpu_profile_id` bigint unsigned DEFAULT NULL COMMENT 'id of the vGPU profile.',
`bus_address` varchar(255) NOT NULL COMMENT 'PCI bus address of the GPU device',
`type` varchar(32) NOT NULL COMMENT 'type of the GPU device. PCI or MDEV',
`host_id` bigint unsigned NOT NULL COMMENT 'id of the host where GPU is installed',
`vm_id` bigint unsigned DEFAULT NULL COMMENT 'id of the VM using this GPU device',
`numa_node` varchar(255) DEFAULT NULL COMMENT 'NUMA node of the GPU device',
`pci_root` varchar(255) DEFAULT NULL COMMENT 'PCI root of the GPU device',
`parent_gpu_device_id` bigint unsigned DEFAULT NULL COMMENT 'id of the parent GPU device. null if it is a physical GPU device and for vGPUs points to the actual GPU',
`state` varchar(32) NOT NULL COMMENT 'state of the GPU device',
`managed_state` varchar(32) NOT NULL COMMENT 'resource state of the GPU device',
PRIMARY KEY (`id`),
UNIQUE KEY (`bus_address`, `host_id`),
CONSTRAINT `fk_gpu_devices__card_id` FOREIGN KEY (`card_id`) REFERENCES `gpu_card` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_gpu_devices__host_id` FOREIGN KEY (`host_id`) REFERENCES `host` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_gpu_devices__vm_id` FOREIGN KEY (`vm_id`) REFERENCES `vm_instance` (`id`) ON DELETE SET NULL,
CONSTRAINT `fk_gpu_devices__parent_gpu_device_id` FOREIGN KEY (`parent_gpu_device_id`) REFERENCES `gpu_device` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='GPU devices installed on hosts';
-- Add references to GPU tables
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.service_offering', 'vgpu_profile_id', 'bigint unsigned DEFAULT NULL COMMENT "vgpu profile ID"');
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.service_offering', 'gpu_count', 'int unsigned DEFAULT NULL COMMENT "number of GPUs"');
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.service_offering', 'gpu_display', 'boolean DEFAULT false COMMENT "enable GPU display"');
CALL `cloud`.`IDEMPOTENT_DROP_FOREIGN_KEY`('cloud.service_offering','fk_service_offering__vgpu_profile_id');
CALL `cloud`.`IDEMPOTENT_ADD_FOREIGN_KEY`('cloud.service_offering', 'fk_service_offering__vgpu_profile_id', '(vgpu_profile_id)', '`vgpu_profile`(`id`)');
-- Netris Plugin
CREATE TABLE `cloud`.`netris_providers` (
`id` bigint unsigned NOT NULL auto_increment COMMENT 'id',

View File

@ -64,6 +64,8 @@ select
`cpucount`.`count` AS `cpuTotal`,
`memorylimit`.`max` AS `memoryLimit`,
`memorycount`.`count` AS `memoryTotal`,
`gpulimit`.`max` AS `gpuLimit`,
`gpucount`.`count` AS `gpuTotal`,
`primary_storage_limit`.`max` AS `primaryStorageLimit`,
`primary_storage_count`.`count` AS `primaryStorageTotal`,
`secondary_storage_limit`.`max` AS `secondaryStorageLimit`,
@ -156,6 +158,12 @@ from
`cloud`.`resource_count` memorycount ON account.id = memorycount.account_id
and memorycount.type = 'memory' and memorycount.tag IS NULL
left join
`cloud`.`resource_limit` gpulimit ON account.id = gpulimit.account_id
and gpulimit.type = 'gpu' and gpulimit.tag IS NULL
left join
`cloud`.`resource_count` gpucount ON account.id = gpucount.account_id
and gpucount.type = 'gpu' and gpucount.tag IS NULL
left join
`cloud`.`resource_limit` primary_storage_limit ON account.id = primary_storage_limit.account_id
and primary_storage_limit.type = 'primary_storage' and primary_storage_limit.tag IS NULL
left join

View File

@ -55,6 +55,8 @@ select
`cpucount`.`count` AS `cpuTotal`,
`memorylimit`.`max` AS `memoryLimit`,
`memorycount`.`count` AS `memoryTotal`,
`gpulimit`.`max` AS `gpuLimit`,
`gpucount`.`count` AS `gpuTotal`,
`primary_storage_limit`.`max` AS `primaryStorageLimit`,
`primary_storage_count`.`count` AS `primaryStorageTotal`,
`secondary_storage_limit`.`max` AS `secondaryStorageLimit`,
@ -130,6 +132,12 @@ from
`cloud`.`resource_count` memorycount ON domain.id = memorycount.domain_id
and memorycount.type = 'memory' and memorycount.tag IS NULL
left join
`cloud`.`resource_limit` gpulimit ON domain.id = gpulimit.domain_id
and gpulimit.type = 'gpu' and gpulimit.tag IS NULL
left join
`cloud`.`resource_count` gpucount ON domain.id = gpucount.domain_id
and gpucount.type = 'gpu' and gpucount.tag IS NULL
left join
`cloud`.`resource_limit` primary_storage_limit ON domain.id = primary_storage_limit.domain_id
and primary_storage_limit.type = 'primary_storage' and primary_storage_limit.tag IS NULL
left join

View File

@ -73,6 +73,18 @@ SELECT
`vsphere_storage_policy`.`value` AS `vsphere_storage_policy`,
`lease_duration_details`.`value` AS `lease_duration`,
`lease_expiry_action_details`.`value` AS `lease_expiry_action`,
`gpu_card`.`id` AS `gpu_card_id`,
`gpu_card`.`uuid` AS `gpu_card_uuid`,
`gpu_card`.`name` AS `gpu_card_name`,
`vgpu_profile`.`id` AS `vgpu_profile_id`,
`vgpu_profile`.`uuid` AS `vgpu_profile_uuid`,
`vgpu_profile`.`name` AS `vgpu_profile_name`,
`vgpu_profile`.`video_ram` AS `vgpu_profile_video_ram`,
`vgpu_profile`.`max_heads` AS `vgpu_profile_max_heads`,
`vgpu_profile`.`max_resolution_x` AS `vgpu_profile_max_resolution_x`,
`vgpu_profile`.`max_resolution_y` AS `vgpu_profile_max_resolution_y`,
`service_offering`.`gpu_count` AS `gpu_count`,
`service_offering`.`gpu_display` AS `gpu_display`,
GROUP_CONCAT(DISTINCT(domain.id)) AS domain_id,
GROUP_CONCAT(DISTINCT(domain.uuid)) AS domain_uuid,
GROUP_CONCAT(DISTINCT(domain.name)) AS domain_name,
@ -89,6 +101,10 @@ FROM
INNER JOIN
`cloud`.`disk_offering` ON service_offering.disk_offering_id = disk_offering.id
LEFT JOIN
`cloud`.`vgpu_profile` ON service_offering.vgpu_profile_id = vgpu_profile.id
LEFT JOIN
`cloud`.`gpu_card` ON vgpu_profile.card_id = gpu_card.id
LEFT JOIN
`cloud`.`service_offering_details` AS `domain_details` ON `domain_details`.`service_offering_id` = `service_offering`.`id` AND `domain_details`.`name`='domainid'
LEFT JOIN
`cloud`.`domain` AS `domain` ON FIND_IN_SET(`domain`.`id`, `domain_details`.`value`)

View File

@ -103,6 +103,17 @@ SELECT
`backup_offering`.`uuid` AS `backup_offering_uuid`,
`backup_offering`.`id` AS `backup_offering_id`,
`service_offering`.`name` AS `service_offering_name`,
`service_offering`.`vgpu_profile_id` AS `vgpu_profile_id`,
`vgpu_profile`.`uuid` AS `vgpu_profile_uuid`,
`vgpu_profile`.`name` AS `vgpu_profile_name`,
`vgpu_profile`.`video_ram` AS `vgpu_profile_video_ram`,
`vgpu_profile`.`max_heads` AS `vgpu_profile_max_heads`,
`vgpu_profile`.`max_resolution_x` AS `vgpu_profile_max_resolution_x`,
`vgpu_profile`.`max_resolution_y` AS `vgpu_profile_max_resolution_y`,
`gpu_card`.`id` AS `gpu_card_id`,
`gpu_card`.`uuid` AS `gpu_card_uuid`,
`gpu_card`.`name` AS `gpu_card_name`,
`service_offering`.`gpu_count` AS `gpu_count`,
`disk_offering`.`name` AS `disk_offering_name`,
`backup_offering`.`name` AS `backup_offering_name`,
`storage_pool`.`id` AS `pool_id`,
@ -174,7 +185,7 @@ SELECT
`lease_expiry_action`.`value` AS `lease_expiry_action`,
`lease_action_execution`.`value` AS `lease_action_execution`
FROM
(((((((((((((((((((((((((((((((((((`user_vm`
(((((((((((((((((((((((((((((((((((((`user_vm`
JOIN `vm_instance` ON (((`vm_instance`.`id` = `user_vm`.`id`)
AND ISNULL(`vm_instance`.`removed`))))
JOIN `account` ON ((`vm_instance`.`account_id` = `account`.`id`)))
@ -192,6 +203,8 @@ FROM
LEFT JOIN `service_offering` ON ((`vm_instance`.`service_offering_id` = `service_offering`.`id`)))
LEFT JOIN `disk_offering` `svc_disk_offering` ON ((`volumes`.`disk_offering_id` = `svc_disk_offering`.`id`)))
LEFT JOIN `disk_offering` ON ((`volumes`.`disk_offering_id` = `disk_offering`.`id`)))
LEFT JOIN `vgpu_profile` ON ((`service_offering`.`vgpu_profile_id` = `vgpu_profile`.`id`)))
LEFT JOIN `gpu_card` ON ((`vgpu_profile`.`card_id` = `gpu_card`.`id`)))
LEFT JOIN `backup_offering` ON ((`vm_instance`.`backup_offering_id` = `backup_offering`.`id`)))
LEFT JOIN `storage_pool` ON ((`volumes`.`pool_id` = `storage_pool`.`id`)))
LEFT JOIN `security_group_vm_map` ON ((`vm_instance`.`id` = `security_group_vm_map`.`instance_id`)))

View File

@ -0,0 +1,57 @@
/*
* 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 com.cloud.gpu.dao;
import com.cloud.gpu.GpuCardVO;
import com.cloud.utils.db.SearchCriteria;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@RunWith(MockitoJUnitRunner.class)
public class GpuCardDaoImplTest {
@Spy
@InjectMocks
GpuCardDaoImpl gpuCardDaoImpl = new GpuCardDaoImpl();
@Test
public void findByVendorIdAndDeviceId() {
doReturn(mock(GpuCardVO.class)).when(gpuCardDaoImpl).findOneBy(any(SearchCriteria.class));
GpuCardVO gpuCard = gpuCardDaoImpl.findByVendorIdAndDeviceId("0d1a", "1a3b");
Assert.assertNotNull("Expected non-null gpu card", gpuCard);
ArgumentCaptor<SearchCriteria> scCaptor = ArgumentCaptor.forClass(SearchCriteria.class);
verify(gpuCardDaoImpl).findOneBy(scCaptor.capture());
Assert.assertEquals("Expected correct where clause",
"gpu_card.vendor_id = ? AND gpu_card.device_id = ?",
scCaptor.getValue().getWhereClause().trim());
}
}

View File

@ -0,0 +1,277 @@
/*
* 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 com.cloud.gpu.dao;
import com.cloud.gpu.GpuDeviceVO;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.SearchCriteria;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Collections;
import java.util.List;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class GpuDeviceDaoImplTest {
@Spy
@InjectMocks
GpuDeviceDaoImpl gpuDeviceDao = new GpuDeviceDaoImpl();
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void listByIds_emptyList() {
List<GpuDeviceVO> devices = gpuDeviceDao.listByIds(null);
Assert.assertTrue("Expected empty list", devices.isEmpty());
devices = gpuDeviceDao.listByIds(Collections.emptyList());
Assert.assertTrue("Expected empty list", devices.isEmpty());
}
@Test
public void listByIds() {
doReturn(List.of(mock(GpuDeviceVO.class))).when(gpuDeviceDao).listBy(any(SearchCriteria.class));
List<GpuDeviceVO> devices = gpuDeviceDao.listByIds(List.of(1L, 2L, 3L));
Assert.assertFalse("Expected non empty list", devices.isEmpty());
ArgumentCaptor<SearchCriteria> scCaptor = ArgumentCaptor.forClass(SearchCriteria.class);
verify(gpuDeviceDao).listBy(scCaptor.capture());
SearchCriteria<GpuDeviceVO> sc = scCaptor.getValue();
Assert.assertEquals("Expected correct where clause", "gpu_device.id IN (?,?,?)", sc.getWhereClause().trim());
}
@Test
public void findByHostIdAndBusAddress() {
doReturn(mock(GpuDeviceVO.class)).when(gpuDeviceDao).findOneBy(any(SearchCriteria.class));
GpuDeviceVO device = gpuDeviceDao.findByHostIdAndBusAddress(1L, "0000:00:1f.6");
Assert.assertNotNull("Expected non-null device", device);
ArgumentCaptor<SearchCriteria> scCaptor = ArgumentCaptor.forClass(SearchCriteria.class);
verify(gpuDeviceDao).findOneBy(scCaptor.capture());
Assert.assertEquals("Expected correct where clause", "gpu_device.host_id = ? AND gpu_device.bus_address = ?",
scCaptor.getValue().getWhereClause().trim());
}
@Test
public void listByHostId() {
doReturn(List.of(mock(GpuDeviceVO.class))).when(gpuDeviceDao).listBy(any(SearchCriteria.class));
List<GpuDeviceVO> devices = gpuDeviceDao.listByHostId(1L);
Assert.assertFalse("Expected non empty list", devices.isEmpty());
ArgumentCaptor<SearchCriteria> scCaptor = ArgumentCaptor.forClass(SearchCriteria.class);
verify(gpuDeviceDao).listBy(scCaptor.capture());
Assert.assertEquals("Expected correct where clause", "gpu_device.host_id = ?",
scCaptor.getValue().getWhereClause().trim());
}
@Test
public void listByVmId() {
doReturn(List.of(mock(GpuDeviceVO.class))).when(gpuDeviceDao).listBy(any(SearchCriteria.class));
List<GpuDeviceVO> devices = gpuDeviceDao.listByVmId(1L);
Assert.assertFalse("Expected non empty list", devices.isEmpty());
ArgumentCaptor<SearchCriteria> scCaptor = ArgumentCaptor.forClass(SearchCriteria.class);
verify(gpuDeviceDao).listBy(scCaptor.capture());
Assert.assertEquals("Expected correct where clause", "gpu_device.vm_id = ?",
scCaptor.getValue().getWhereClause().trim());
}
@Test
public void isVgpuProfileInUse() {
doReturn(1).when(gpuDeviceDao).getCount(any(SearchCriteria.class));
boolean vgpuProfileInUse = gpuDeviceDao.isVgpuProfileInUse(1L);
Assert.assertTrue("Expected vGPU profile to be in use", vgpuProfileInUse);
ArgumentCaptor<SearchCriteria> scCaptor = ArgumentCaptor.forClass(SearchCriteria.class);
verify(gpuDeviceDao).getCount(scCaptor.capture());
Assert.assertEquals("Expected correct where clause", "gpu_device.vgpu_profile_id = ?",
scCaptor.getValue().getWhereClause().trim());
}
@Test
public void isGpuCardInUse() {
doReturn(1).when(gpuDeviceDao).getCount(any(SearchCriteria.class));
boolean vgpuProfileInUse = gpuDeviceDao.isGpuCardInUse(1L);
Assert.assertTrue("Expected GPU Card to be in use", vgpuProfileInUse);
ArgumentCaptor<SearchCriteria> scCaptor = ArgumentCaptor.forClass(SearchCriteria.class);
verify(gpuDeviceDao).getCount(scCaptor.capture());
Assert.assertEquals("Expected correct where clause", "gpu_device.card_id = ?",
scCaptor.getValue().getWhereClause().trim());
}
@Test
public void listByHostAndVm() {
doReturn(List.of(mock(GpuDeviceVO.class))).when(gpuDeviceDao).search(any(SearchCriteria.class), any());
List<GpuDeviceVO> devices = gpuDeviceDao.listByHostAndVm(1L, 2L);
Assert.assertFalse("Expected non empty list", devices.isEmpty());
ArgumentCaptor<SearchCriteria> scCaptor = ArgumentCaptor.forClass(SearchCriteria.class);
ArgumentCaptor<Filter> filterCaptor = ArgumentCaptor.forClass(Filter.class);
verify(gpuDeviceDao).search(scCaptor.capture(), filterCaptor.capture());
Assert.assertEquals("Expected correct where clause", "gpu_device.host_id = ? AND gpu_device.vm_id = ?",
scCaptor.getValue().getWhereClause().trim());
Assert.assertNull("Expected no filter", filterCaptor.getValue());
}
@Test
public void listDevicesForAllocation() {
doReturn(List.of(mock(GpuDeviceVO.class))).when(gpuDeviceDao).search(any(SearchCriteria.class), any());
List<GpuDeviceVO> devices = gpuDeviceDao.listDevicesForAllocation(1L, 2L);
Assert.assertFalse("Expected non empty list", devices.isEmpty());
ArgumentCaptor<SearchCriteria> scCaptor = ArgumentCaptor.forClass(SearchCriteria.class);
ArgumentCaptor<Filter> filterCaptor = ArgumentCaptor.forClass(Filter.class);
verify(gpuDeviceDao).search(scCaptor.capture(), filterCaptor.capture());
Assert.assertEquals("Expected correct where clause",
"gpu_device.host_id = ? AND gpu_device.vgpu_profile_id=? AND gpu_device.state = ? AND gpu_device"
+ ".managed_state = ? AND gpu_device.type != ?",
scCaptor.getValue().getWhereClause().trim());
Assert.assertNull("Expected no filter", filterCaptor.getValue());
}
@Test
public void searchAndCountGpuDevices() {
}
@Test
public void getDistinctGpuCardIds_no_devices() {
doReturn(null).when(gpuDeviceDao).listBy(any(SearchCriteria.class));
List<Long> cardIds = gpuDeviceDao.getDistinctGpuCardIds();
Assert.assertTrue("Expected empty list", cardIds.isEmpty());
ArgumentCaptor<SearchCriteria> scCaptor = ArgumentCaptor.forClass(SearchCriteria.class);
verify(gpuDeviceDao).listBy(scCaptor.capture());
Assert.assertEquals("Expected correct where clause", "", scCaptor.getValue().getWhereClause().trim());
}
@Test
public void getDistinctGpuCardIds() {
GpuDeviceVO device1 = mock(GpuDeviceVO.class);
GpuDeviceVO device2 = mock(GpuDeviceVO.class);
GpuDeviceVO device3 = mock(GpuDeviceVO.class);
when(device1.getCardId()).thenReturn(1L);
when(device2.getCardId()).thenReturn(2L);
when(device3.getCardId()).thenReturn(1L);
doReturn(List.of(device1, device2, device3)).when(gpuDeviceDao).listBy(any(SearchCriteria.class));
List<Long> cardIds = gpuDeviceDao.getDistinctGpuCardIds();
Assert.assertEquals("Expected 2 card IDs", 2, cardIds.size());
Assert.assertTrue("Expected card ID 1 in list", cardIds.contains(1L));
Assert.assertTrue("Expected card ID 2 in list", cardIds.contains(2L));
ArgumentCaptor<SearchCriteria> scCaptor = ArgumentCaptor.forClass(SearchCriteria.class);
verify(gpuDeviceDao).listBy(scCaptor.capture());
Assert.assertEquals("Expected correct where clause", "", scCaptor.getValue().getWhereClause().trim());
}
@Test
public void getDistinctVgpuProfileIds_no_devices() {
doReturn(null).when(gpuDeviceDao).listBy(any(SearchCriteria.class));
List<Long> cardIds = gpuDeviceDao.getDistinctVgpuProfileIds();
Assert.assertTrue("Expected empty list", cardIds.isEmpty());
ArgumentCaptor<SearchCriteria> scCaptor = ArgumentCaptor.forClass(SearchCriteria.class);
verify(gpuDeviceDao).listBy(scCaptor.capture());
Assert.assertEquals("Expected correct where clause", "", scCaptor.getValue().getWhereClause().trim());
}
@Test
public void getDistinctVgpuProfileIds() {
GpuDeviceVO device1 = mock(GpuDeviceVO.class);
GpuDeviceVO device2 = mock(GpuDeviceVO.class);
GpuDeviceVO device3 = mock(GpuDeviceVO.class);
when(device1.getVgpuProfileId()).thenReturn(1L);
when(device2.getVgpuProfileId()).thenReturn(2L);
when(device3.getVgpuProfileId()).thenReturn(1L);
doReturn(List.of(device1, device2, device3)).when(gpuDeviceDao).listBy(any(SearchCriteria.class));
List<Long> cardIds = gpuDeviceDao.getDistinctVgpuProfileIds();
Assert.assertEquals("Expected 2 VgpuProfile IDs", 2, cardIds.size());
Assert.assertTrue("Expected VgpuProfile ID 1 in list", cardIds.contains(1L));
Assert.assertTrue("Expected VgpuProfile ID 2 in list", cardIds.contains(2L));
ArgumentCaptor<SearchCriteria> scCaptor = ArgumentCaptor.forClass(SearchCriteria.class);
verify(gpuDeviceDao).listBy(scCaptor.capture());
Assert.assertEquals("Expected correct where clause", "", scCaptor.getValue().getWhereClause().trim());
}
@Test
public void listByParentGpuDeviceId() {
doReturn(List.of(mock(GpuDeviceVO.class))).when(gpuDeviceDao).listBy(any(SearchCriteria.class));
List<GpuDeviceVO> devices = gpuDeviceDao.listByParentGpuDeviceId(1L);
Assert.assertFalse("Expected non empty list", devices.isEmpty());
ArgumentCaptor<SearchCriteria> scCaptor = ArgumentCaptor.forClass(SearchCriteria.class);
verify(gpuDeviceDao).listBy(scCaptor.capture());
Assert.assertEquals("Expected correct where clause", "gpu_device.parent_gpu_device_id = ?",
scCaptor.getValue().getWhereClause().trim());
}
}

View File

@ -0,0 +1,70 @@
/*
* 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 com.cloud.gpu.dao;
import com.cloud.gpu.VgpuProfileVO;
import com.cloud.utils.db.SearchCriteria;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@RunWith(MockitoJUnitRunner.class)
public class VgpuProfileDaoImplTest {
@Spy
@InjectMocks
VgpuProfileDaoImpl vgpuProfileDaoImpl = new VgpuProfileDaoImpl();
@Test
public void findByNameAndCardId() {
doReturn(mock(VgpuProfileVO.class)).when(vgpuProfileDaoImpl).findOneBy(any(SearchCriteria.class));
VgpuProfileVO vgpuProfile = vgpuProfileDaoImpl.findByNameAndCardId("test-profile", 1L);
Assert.assertNotNull("Expected non-null vgpu profile", vgpuProfile);
ArgumentCaptor<SearchCriteria> scCaptor = ArgumentCaptor.forClass(SearchCriteria.class);
verify(vgpuProfileDaoImpl).findOneBy(scCaptor.capture());
Assert.assertEquals("Expected correct where clause",
"vgpu_profile.name = ? AND vgpu_profile.card_id=?",
scCaptor.getValue().getWhereClause().trim());
}
@Test
public void removeByCardId() {
doReturn(1).when(vgpuProfileDaoImpl).remove(any(SearchCriteria.class));
int removed = vgpuProfileDaoImpl.removeByCardId(123L);
Assert.assertEquals("Expected one vgpu profile removed", 1, removed);
ArgumentCaptor<SearchCriteria> scCaptor = ArgumentCaptor.forClass(SearchCriteria.class);
verify(vgpuProfileDaoImpl).remove(scCaptor.capture());
Assert.assertEquals("Expected correct where clause", "vgpu_profile.card_id=?",
scCaptor.getValue().getWhereClause().trim());
}
}

View File

@ -74,6 +74,7 @@ import org.apache.cloudstack.command.CommandInfo;
import org.apache.cloudstack.command.ReconcileCommandService;
import org.apache.cloudstack.command.ReconcileCommandUtils;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
import org.apache.cloudstack.gpu.GpuDevice;
import org.apache.cloudstack.storage.command.browser.ListDataStoreObjectsCommand;
import org.apache.cloudstack.storage.configdrive.ConfigDrive;
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
@ -103,9 +104,9 @@ import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.Logger;
import org.apache.xerces.impl.xpath.regex.Match;
import org.joda.time.Duration;
import org.libvirt.Connect;
@ -130,7 +131,6 @@ import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.HostVmStateReportEntry;
@ -143,6 +143,7 @@ import com.cloud.agent.api.SetupGuestNetworkCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupRoutingCommand;
import com.cloud.agent.api.StartupStorageCommand;
import com.cloud.agent.api.VgpuTypesInfo;
import com.cloud.agent.api.VmDiskStatsEntry;
import com.cloud.agent.api.VmNetworkStatsEntry;
import com.cloud.agent.api.VmStatsEntry;
@ -213,8 +214,8 @@ import com.cloud.network.Networks.IsolationType;
import com.cloud.network.Networks.RouterPrivateIpStrategy;
import com.cloud.network.Networks.TrafficType;
import com.cloud.resource.AgentStatusUpdater;
import com.cloud.resource.ResourceStatusUpdater;
import com.cloud.resource.RequestWrapper;
import com.cloud.resource.ResourceStatusUpdater;
import com.cloud.resource.ServerResource;
import com.cloud.resource.ServerResourceBase;
import com.cloud.storage.JavaStorageLayer;
@ -241,6 +242,10 @@ import com.cloud.vm.VirtualMachine.PowerState;
import com.cloud.vm.VmDetailConstants;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/**
* LibvirtComputingResource execute requests on the computing/routing host using
@ -379,6 +384,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
private String modifyVlanPath;
private String versionStringPath;
private String gpuDiscoveryPath;
private String patchScriptPath;
private String createVmPath;
private String manageSnapshotPath;
@ -487,12 +493,15 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
protected String agentHooksBasedir = "/etc/cloudstack/agent/hooks";
protected String agentHooksLibvirtXmlScript = "libvirt-vm-xml-transformer.groovy";
protected String agentHooksLibvirtXmlShellScript = "libvirt-vm-xml-transformer.sh";
protected String agentHooksLibvirtXmlMethod = "transform";
protected String agentHooksVmOnStartScript = "libvirt-vm-state-change.groovy";
protected String agentHooksVmOnStartShellScript = "libvirt-vm-state-change.sh";
protected String agentHooksVmOnStartMethod = "onStart";
protected String agentHooksVmOnStopScript = "libvirt-vm-state-change.groovy";
protected String agentHooksVmOnStopShellScript = "libvirt-vm-state-change.sh";
protected String agentHooksVmOnStopMethod = "onStop";
protected static final String LOCAL_STORAGE_PATH = "local.storage.path";
@ -686,15 +695,15 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
}
public LibvirtKvmAgentHook getTransformer() throws IOException {
return new LibvirtKvmAgentHook(agentHooksBasedir, agentHooksLibvirtXmlScript, agentHooksLibvirtXmlMethod);
return new LibvirtKvmAgentHook(agentHooksBasedir, agentHooksLibvirtXmlScript, agentHooksLibvirtXmlShellScript, agentHooksLibvirtXmlMethod);
}
public LibvirtKvmAgentHook getStartHook() throws IOException {
return new LibvirtKvmAgentHook(agentHooksBasedir, agentHooksVmOnStartScript, agentHooksVmOnStartMethod);
return new LibvirtKvmAgentHook(agentHooksBasedir, agentHooksVmOnStartScript, agentHooksVmOnStartShellScript, agentHooksVmOnStartMethod);
}
public LibvirtKvmAgentHook getStopHook() throws IOException {
return new LibvirtKvmAgentHook(agentHooksBasedir, agentHooksVmOnStopScript, agentHooksVmOnStopMethod);
return new LibvirtKvmAgentHook(agentHooksBasedir, agentHooksVmOnStopScript, agentHooksVmOnStopShellScript, agentHooksVmOnStopMethod);
}
public LibvirtUtilitiesHelper getLibvirtUtilitiesHelper() {
@ -1039,6 +1048,11 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
throw new ConfigurationException("Unable to find versions.sh");
}
gpuDiscoveryPath = Script.findScript(kvmScriptsDir, "gpudiscovery.sh");
if (gpuDiscoveryPath == null) {
throw new ConfigurationException("Unable to find gpudiscovery.sh");
}
patchScriptPath = Script.findScript(kvmScriptsDir, "patch.sh");
if (patchScriptPath == null) {
throw new ConfigurationException("Unable to find patch.sh");
@ -1593,18 +1607,27 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
agentHooksLibvirtXmlScript = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.AGENT_HOOKS_LIBVIRT_VM_XML_TRANSFORMER_SCRIPT);
LOGGER.debug("agent.hooks.libvirt_vm_xml_transformer.script is " + agentHooksLibvirtXmlScript);
agentHooksLibvirtXmlShellScript = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.AGENT_HOOKS_LIBVIRT_VM_XML_TRANSFORMER_SHELL_SCRIPT);
LOGGER.debug("agent.hooks.libvirt_vm_xml_transformer.shell_script is " + agentHooksLibvirtXmlShellScript);
agentHooksLibvirtXmlMethod = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.AGENT_HOOKS_LIBVIRT_VM_XML_TRANSFORMER_METHOD);
LOGGER.debug("agent.hooks.libvirt_vm_xml_transformer.method is " + agentHooksLibvirtXmlMethod);
agentHooksVmOnStartScript = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.AGENT_HOOKS_LIBVIRT_VM_ON_START_SCRIPT);
LOGGER.debug("agent.hooks.libvirt_vm_on_start.script is " + agentHooksVmOnStartScript);
agentHooksVmOnStartShellScript = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.AGENT_HOOKS_LIBVIRT_VM_ON_START_SHELL_SCRIPT);
LOGGER.debug("agent.hooks.libvirt_vm_on_start.shell_script is " + agentHooksVmOnStartShellScript);
agentHooksVmOnStartMethod = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.AGENT_HOOKS_LIBVIRT_VM_ON_START_METHOD);
LOGGER.debug("agent.hooks.libvirt_vm_on_start.method is " + agentHooksVmOnStartMethod);
agentHooksVmOnStopScript = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.AGENT_HOOKS_LIBVIRT_VM_ON_STOP_SCRIPT);
LOGGER.debug("agent.hooks.libvirt_vm_on_stop.script is " + agentHooksVmOnStopScript);
agentHooksVmOnStopShellScript = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.AGENT_HOOKS_LIBVIRT_VM_ON_STOP_SHELL_SCRIPT);
LOGGER.debug("agent.hooks.libvirt_vm_on_stop.shell_script is " + agentHooksVmOnStopShellScript);
agentHooksVmOnStopMethod = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.AGENT_HOOKS_LIBVIRT_VM_ON_STOP_METHOD);
LOGGER.debug("agent.hooks.libvirt_vm_on_stop.method is " + agentHooksVmOnStopMethod);
}
@ -1955,6 +1978,173 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
return true;
}
public List<VgpuTypesInfo> getGpuDevices() {
LOGGER.debug("Executing GPU discovery script at: {}", gpuDiscoveryPath);
final Script command = new Script(gpuDiscoveryPath, Duration.standardSeconds(30), LOGGER);
OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser();
String result = command.execute(parser);
if (result == null) {
LOGGER.debug("GPU discovery command executed successfully");
result = parser.getLines();
}
if (result == null || result.trim().isEmpty()) {
LOGGER.error("GPU discovery failed: command returned null or empty result. Script path: {}, Exit code: {}",
gpuDiscoveryPath, command.getExitValue());
return Collections.emptyList();
}
LOGGER.debug("GPU discovery result: {}", result);
// This will be used to update the GPU device list when agent on a host is unavailable or the VM is imported.
return parseGpuDevicesFromResult(result);
}
protected List<VgpuTypesInfo> parseGpuDevicesFromResult(String result) {
List<VgpuTypesInfo> gpuDevices = new ArrayList<>();
try {
JsonParser jsonParser = new JsonParser();
JsonArray jsonArray = jsonParser.parse(result).getAsJsonObject().get("gpus").getAsJsonArray();
for (JsonElement jsonElement : jsonArray) {
JsonObject jsonObject = jsonElement.getAsJsonObject();
String busAddress = jsonObject.get("pci_address").getAsString();
String vendorId = jsonObject.get("vendor_id").getAsString();
String vendorName = jsonObject.get("vendor").getAsString();
String deviceId = jsonObject.get("device_id").getAsString();
String deviceName = jsonObject.get("device").getAsString();
// vgpu instances uses mdev uuid
// vf instances uses vf_pci_address
JsonArray vgpuInstances = jsonObject.get("vgpu_instances").getAsJsonArray();
JsonArray vfInstances = jsonObject.get("vf_instances").getAsJsonArray();
JsonObject fullPassthrough = jsonObject.get("full_passthrough").getAsJsonObject();
boolean fullPassthroughEnabled = fullPassthrough.get("enabled").getAsInt() == 1;
String numaNode = getJsonStringValueOrNull(jsonObject, "numa_node");
String pciRoot = getJsonStringValueOrNull(jsonObject, "pci_root");
Long maxInstances = getJsonLongValueOrNull(jsonObject, "max_instances");
Long videoRam = getJsonLongValueOrNull(jsonObject, "video_ram");
Long maxHeads = getJsonLongValueOrNull(jsonObject, "max_heads");
Long maxResolutionX = getJsonLongValueOrNull(jsonObject, "max_resolution_x");
Long maxResolutionY = getJsonLongValueOrNull(jsonObject, "max_resolution_y");
VgpuTypesInfo vgpuType = new VgpuTypesInfo(GpuDevice.DeviceType.PCI, vendorName + " " + deviceName,
"passthrough", busAddress, vendorId, vendorName, deviceId, deviceName, numaNode, pciRoot);
vgpuType.setMaxVgpuPerGpu(maxInstances);
vgpuType.setVideoRam(videoRam);
vgpuType.setMaxHeads(maxHeads);
vgpuType.setMaxResolutionX(maxResolutionX);
vgpuType.setMaxResolutionY(maxResolutionY);
if (fullPassthroughEnabled) {
vgpuType.setPassthroughEnabled(true);
} else {
vgpuType.setPassthroughEnabled(false);
}
vgpuType.setVmName(getJsonStringValueOrNull(fullPassthrough, "used_by_vm"));
gpuDevices.add(vgpuType);
for (JsonElement vgpuInstance : vgpuInstances) {
VgpuTypesInfo vgpu = getGpuDeviceFromVgpuInstance(vgpuInstance, busAddress, vendorId, vendorName,
deviceId, deviceName, numaNode, pciRoot);
if (vgpu != null) {
gpuDevices.add(vgpu);
}
}
for (JsonElement vfInstance : vfInstances) {
VgpuTypesInfo vf = getGpuDeviceFromVfInstance(vfInstance, busAddress, vendorId, vendorName,
deviceId, deviceName, numaNode, pciRoot);
if (vf != null) {
gpuDevices.add(vf);
}
}
}
} catch (Exception e) {
LOGGER.error("Failed to parse GPU discovery result: {}", e.getMessage(), e);
}
return gpuDevices;
}
protected VgpuTypesInfo getGpuDeviceFromVgpuInstance(JsonElement vgpuInstance, String busAddress, String vendorId,
String vendorName, String deviceId, String deviceName, String numaNode, String pciRoot) {
JsonObject vgpuInstanceJsonObject = vgpuInstance.getAsJsonObject();
String mdevUuid = getJsonStringValueOrNull(vgpuInstanceJsonObject, "mdev_uuid");
String profileName = getJsonStringValueOrNull(vgpuInstanceJsonObject, "profile_name");
if (profileName == null || profileName.isEmpty()) {
return null; // Skip if profile name is not provided
}
Long maxInstances = getJsonLongValueOrNull(vgpuInstanceJsonObject, "max_instances");
Long videoRam = getJsonLongValueOrNull(vgpuInstanceJsonObject, "video_ram");
Long maxHeads = getJsonLongValueOrNull(vgpuInstanceJsonObject, "max_heads");
Long maxResolutionX = getJsonLongValueOrNull(vgpuInstanceJsonObject, "max_resolution_x");
Long maxResolutionY = getJsonLongValueOrNull(vgpuInstanceJsonObject, "max_resolution_y");
VgpuTypesInfo device = new VgpuTypesInfo(GpuDevice.DeviceType.MDEV, vendorName + " " + deviceName, profileName, mdevUuid, vendorId, vendorName, deviceId, deviceName, numaNode, pciRoot);
device.setParentBusAddress(busAddress);
device.setMaxVgpuPerGpu(maxInstances);
device.setVideoRam(videoRam);
device.setMaxHeads(maxHeads);
device.setMaxResolutionX(maxResolutionX);
device.setMaxResolutionY(maxResolutionY);
device.setVmName(getJsonStringValueOrNull(vgpuInstance.getAsJsonObject(), "used_by_vm"));
return device;
}
protected VgpuTypesInfo getGpuDeviceFromVfInstance(JsonElement vfInstance, String busAddress, String vendorId,
String vendorName, String deviceId, String deviceName, String numaNode, String pciRoot) {
JsonObject vfInstanceJsonObject = vfInstance.getAsJsonObject();
String vfPciAddress = vfInstanceJsonObject.get("vf_pci_address").getAsString();
String vfProfile = vfInstanceJsonObject.get("vf_profile").getAsString();
if (vfProfile == null || vfProfile.isEmpty()) {
return null; // Skip if profile name is not provided
}
Long maxInstances = getJsonLongValueOrNull(vfInstanceJsonObject, "max_instances");
Long videoRam = getJsonLongValueOrNull(vfInstanceJsonObject, "video_ram");
Long maxHeads = getJsonLongValueOrNull(vfInstanceJsonObject, "max_heads");
Long maxResolutionX = getJsonLongValueOrNull(vfInstanceJsonObject, "max_resolution_x");
Long maxResolutionY = getJsonLongValueOrNull(vfInstanceJsonObject, "max_resolution_y");
VgpuTypesInfo device = new VgpuTypesInfo(GpuDevice.DeviceType.PCI, vendorName + " " + deviceName, vfProfile, vfPciAddress, vendorId, vendorName, deviceId, deviceName, numaNode, pciRoot);
device.setParentBusAddress(busAddress);
device.setMaxVgpuPerGpu(maxInstances);
device.setVideoRam(videoRam);
device.setMaxHeads(maxHeads);
device.setMaxResolutionX(maxResolutionX);
device.setMaxResolutionY(maxResolutionY);
device.setVmName(getJsonStringValueOrNull(vfInstanceJsonObject, "used_by_vm"));
return device;
}
/**
* Safely extracts a string value from a JSON object, returning null if the field is missing or null.
*
* @param jsonObject the JSON object to extract from
* @param fieldName the name of the field to extract
* @return the string value of the field, or null if the field is missing or null
*/
protected String getJsonStringValueOrNull(JsonObject jsonObject, String fieldName) {
JsonElement element = jsonObject.get(fieldName);
if (element == null || element.isJsonNull()) {
return null;
}
return element.getAsString();
}
protected Long getJsonLongValueOrNull(JsonObject jsonObject, String fieldName) {
JsonElement element = jsonObject.get(fieldName);
if (element == null || element.isJsonNull()) {
return null;
}
return element.getAsLong();
}
boolean isDirectAttachedNetwork(final String type) {
if ("untagged".equalsIgnoreCase(type)) {
return true;
@ -2807,6 +2997,10 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
devices.addDevice(createConsoleDef());
devices.addDevice(createGraphicDef(vmTO));
if (vmTO.getGpuDevice() != null && CollectionUtils.isNotEmpty(vmTO.getGpuDevice().getGpuDevices())) {
attachGpuDevices(vmTO, devices);
}
if (!isGuestS390x()) {
devices.addDevice(createTabletInputDef());
}
@ -2834,6 +3028,19 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
return devices;
}
protected void attachGpuDevices(final VirtualMachineTO vmTO, final DevicesDef devicesDef) {
// GPU device is not set for the VM
List<VgpuTypesInfo> gpuDevices = vmTO.getGpuDevice().getGpuDevices();
for (VgpuTypesInfo gpuDevice : gpuDevices) {
LibvirtGpuDef gpu = new LibvirtGpuDef();
gpu.defGpu(gpuDevice);
devicesDef.addDevice(gpu);
LOGGER.info("Attached GPU device " + gpuDevice.getDeviceName() + " to VM " + vmTO.getName());
}
}
protected WatchDogDef createWatchDogDef() {
return new WatchDogDef(watchDogAction, watchDogModel);
}
@ -3947,6 +4154,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
hostDistro = cmd.getHostDetails().get("Host.OS");
}
cmd.setGpuDevices(getGpuDevices());
List<StartupCommand> startupCommands = new ArrayList<>();
startupCommands.add(cmd);
for (int i = 0; i < localStoragePaths.size(); i++) {
@ -6214,5 +6423,4 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
public String getGuestCpuArch() {
return guestCpuArch;
}
}

View File

@ -0,0 +1,102 @@
// 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 com.cloud.hypervisor.kvm.resource;
import com.cloud.agent.api.VgpuTypesInfo;
import org.apache.cloudstack.gpu.GpuDevice;
public class LibvirtGpuDef {
private VgpuTypesInfo vgpuType;
public LibvirtGpuDef() {}
public void defGpu(VgpuTypesInfo vgpuType) {
this.vgpuType = vgpuType;
}
@Override
public String toString() {
StringBuilder gpuBuilder = new StringBuilder();
GpuDevice.DeviceType deviceType = vgpuType.getDeviceType();
if (deviceType == GpuDevice.DeviceType.MDEV) {
// Generate XML for MDEV device (vGPU, including MIG instances)
generateMdevXml(gpuBuilder);
} else {
// Generate XML for PCI device (passthrough GPU or VF)
generatePciXml(gpuBuilder);
}
return gpuBuilder.toString();
}
private void generateMdevXml(StringBuilder gpuBuilder) {
String mdevUuid = vgpuType.getBusAddress(); // For MDEV devices, busAddress contains the UUID
String displayAttribute = vgpuType.isDisplay() ? "on" : "off";
gpuBuilder.append("<hostdev mode='subsystem' type='mdev' managed='no' display='").append(displayAttribute).append("'>\n");
gpuBuilder.append(" <source>\n");
gpuBuilder.append(" <address uuid='").append(mdevUuid).append("'/>\n");
gpuBuilder.append(" </source>\n");
gpuBuilder.append("</hostdev>\n");
}
private void generatePciXml(StringBuilder gpuBuilder) {
String busAddress = vgpuType.getBusAddress();
// For VDI use cases with display=on, ramfb provides early boot framebuffer
// before GPU driver loads. This is critical for:
// - Windows VDI guests (require framebuffer during boot)
// - UEFI/OVMF firmware environments
// - ARM64 hosts (cache coherency issues with traditional VGA)
// - Multi-monitor VDI setups (primary display)
if (vgpuType.isDisplay()) {
gpuBuilder.append("<hostdev mode='subsystem' type='pci' managed='yes' display='on' ramfb='on'>\n");
} else {
// Compute-only workloads don't need display or ramfb
gpuBuilder.append("<hostdev mode='subsystem' type='pci' managed='yes' display='off'>\n");
}
gpuBuilder.append(" <driver name='vfio'/>\n");
gpuBuilder.append(" <source>\n");
// Parse the bus address (e.g., 00:02.0) into domain, bus, slot, function
String domain = "0x0000";
String bus = "0x00";
String slot = "0x00";
String function = "0x0";
if (busAddress != null && !busAddress.isEmpty()) {
String[] parts = busAddress.split(":");
if (parts.length > 1) {
bus = "0x" + parts[0];
String[] slotFunctionParts = parts[1].split("\\.");
if (slotFunctionParts.length > 0) {
slot = "0x" + slotFunctionParts[0];
if (slotFunctionParts.length > 1) {
function = "0x" + slotFunctionParts[1].trim();
}
}
}
}
gpuBuilder.append(" <address domain='").append(domain).append("' bus='").append(bus).append("' slot='")
.append(slot).append("' function='").append(function.trim()).append("'/>\n");
gpuBuilder.append(" </source>\n");
gpuBuilder.append("</hostdev>\n");
}
}

View File

@ -17,6 +17,8 @@
package com.cloud.hypervisor.kvm.resource;
import com.cloud.utils.script.OutputInterpreter;
import com.cloud.utils.script.Script;
import groovy.lang.Binding;
import groovy.lang.GroovyObject;
import groovy.util.GroovyScriptEngine;
@ -25,18 +27,39 @@ import groovy.util.ScriptException;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.codehaus.groovy.runtime.metaclass.MissingMethodExceptionNoStack;
import org.joda.time.Duration;
import java.io.File;
import java.io.IOException;
public class LibvirtKvmAgentHook {
private final String script;
private final String shellScript;
private final String method;
private final GroovyScriptEngine gse;
private final Binding binding = new Binding();
protected Logger logger = LogManager.getLogger(getClass());
public LibvirtKvmAgentHook(String path, String script, String shellScript, String method) throws IOException {
this.script = script;
this.method = method;
File full_path = new File(path, script);
if (!full_path.canRead()) {
logger.warn("Groovy script '" + full_path.toString() + "' is not available. Transformations will not be applied.");
this.gse = null;
} else {
this.gse = new GroovyScriptEngine(path);
}
full_path = new File(path, shellScript);
if (!full_path.canRead()) {
logger.warn("Shell script '" + full_path.toString() + "' is not available. Transformations will not be applied.");
this.shellScript = null;
} else {
this.shellScript = full_path.getAbsolutePath();
}
}
public LibvirtKvmAgentHook(String path, String script, String method) throws IOException {
this.script = script;
this.method = method;
@ -47,31 +70,69 @@ public class LibvirtKvmAgentHook {
} else {
this.gse = new GroovyScriptEngine(path);
}
this.shellScript = null;
}
public boolean isInitialized() {
return this.gse != null;
}
/**
* Sanitizes a string for safe use as a bash command argument by escaping special characters.
* This prevents shell injection and parsing issues when passing multiline content like XML.
*/
String sanitizeBashCommandArgument(String input) {
if (input == null) {
return "";
}
StringBuilder sanitized = new StringBuilder();
for (char c : input.toCharArray()) {
if ("\\\"'`$|&;()<>*?![]{}~".indexOf(c) != -1) {
sanitized.append('\\');
}
sanitized.append(c);
}
return sanitized.toString();
}
public Object handle(Object arg) throws ResourceException, ScriptException {
if (!isInitialized()) {
Object res = arg;
if (isInitialized()) {
GroovyObject cls = (GroovyObject) this.gse.run(this.script, binding);
if (null == cls) {
logger.warn("Groovy object is not received from script '" + this.script + "'.");
return arg;
} else {
Object[] params = {logger, arg};
try {
res = cls.invokeMethod(this.method, params);
} catch (MissingMethodExceptionNoStack e) {
logger.error("Error occurred when calling method from groovy script, {}", e);
res = arg;
}
}
} else {
logger.warn("Groovy scripting engine is not initialized. Data transformation skipped.");
return arg;
}
GroovyObject cls = (GroovyObject) this.gse.run(this.script, binding);
if (null == cls) {
logger.warn("Groovy object is not received from script '" + this.script + "'.");
return arg;
} else {
Object[] params = {logger, arg};
try {
Object res = cls.invokeMethod(this.method, params);
return res;
} catch (MissingMethodExceptionNoStack e) {
logger.error("Error occurred when calling method from groovy script, {}", e);
return arg;
// Shell script
if (this.shellScript != null) {
logger.debug("Executing Shell script for transformation at: {}", this.shellScript);
final Script command = new Script(this.shellScript, Duration.standardSeconds(30), logger);
command.add(String.valueOf(this.method));
command.add(String.valueOf(res));
OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser();
String result = command.execute(parser);
if (result == null) {
logger.debug("GPU discovery command executed successfully");
res = parser.getLines();
} else {
logger.warn("Error occurred when calling script for transformation: {}", result);
}
} else {
logger.debug("No shell script provided for transformation. Data transformation skipped.");
}
return res;
}
}

View File

@ -0,0 +1,37 @@
//
// 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 com.cloud.hypervisor.kvm.resource.wrapper;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.GetGPUStatsAnswer;
import com.cloud.agent.api.GetGPUStatsCommand;
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
import com.cloud.resource.CommandWrapper;
import com.cloud.resource.ResourceWrapper;
@ResourceWrapper(handles = GetGPUStatsCommand.class)
public final class LibvirtGetGPUStatsCommandWrapper extends CommandWrapper<GetGPUStatsCommand, Answer,
LibvirtComputingResource> {
@Override
public Answer execute(final GetGPUStatsCommand command, final LibvirtComputingResource libvirtComputingResource) {
return new GetGPUStatsAnswer(command, libvirtComputingResource.getGpuDevices());
}
}

Some files were not shown because too many files have changed in this diff Show More