Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
Abhishek Kumar 2026-04-02 11:16:15 +05:30
parent 260e6bc5bf
commit bad164c991
37 changed files with 630 additions and 258 deletions

View File

@ -150,7 +150,7 @@ public abstract class BaseDeployVMCmd extends BaseAsyncCreateCustomIdCmd impleme
protected String userData;
@Parameter(name = ApiConstants.USER_DATA_ID, type = CommandType.UUID, entityType = UserDataResponse.class, description = "the ID of the Userdata", since = "4.18")
private Long userdataId;
protected Long userdataId;
@Parameter(name = ApiConstants.USER_DATA_DETAILS, type = CommandType.MAP, description = "used to specify the parameters values for the variables in userdata.", since = "4.18")
private Map userdataDetails;
@ -200,7 +200,7 @@ public abstract class BaseDeployVMCmd extends BaseAsyncCreateCustomIdCmd impleme
@ACL
@Parameter(name = ApiConstants.AFFINITY_GROUP_IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups id that are going to be applied to the virtual machine."
+ " Mutually exclusive with affinitygroupnames parameter")
private List<Long> affinityGroupIdList;
protected List<Long> affinityGroupIdList;
@ACL
@Parameter(name = ApiConstants.AFFINITY_GROUP_NAMES, type = CommandType.LIST, collectionType = CommandType.STRING, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups names that are going to be applied to the virtual machine."

View File

@ -155,6 +155,14 @@ public class DeployVMCmd extends BaseDeployVMCmd {
this.displayVm = displayVm;
}
public void setUserDataId(Long userDataId) {
this.userdataId = userDataId;
}
public void setAffinityGroupIds(List<Long> ids) {
this.affinityGroupIdList = ids;
}
public void setDetails(Map details) {
this.details = details;
}

View File

@ -23,6 +23,7 @@ import com.cloud.cpu.CPU;
import com.cloud.dc.ClusterVO;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDao;
public interface ClusterDao extends GenericDao<ClusterVO, Long> {
@ -62,5 +63,5 @@ public interface ClusterDao extends GenericDao<ClusterVO, Long> {
List<Long> listEnabledClusterIdsByZoneHypervisorArch(Long zoneId, HypervisorType hypervisorType, CPU.CPUArch arch);
List<ClusterVO> listByHypervisorType(HypervisorType hypervisorType);
List<ClusterVO> listByHypervisorType(HypervisorType hypervisorType, Filter filter);
}

View File

@ -38,6 +38,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.org.Grouping;
import com.cloud.org.Managed;
import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.GenericSearchBuilder;
import com.cloud.utils.db.JoinBuilder;
@ -415,9 +416,9 @@ public class ClusterDaoImpl extends GenericDaoBase<ClusterVO, Long> implements C
}
@Override
public List<ClusterVO> listByHypervisorType(HypervisorType hypervisorType) {
public List<ClusterVO> listByHypervisorType(HypervisorType hypervisorType, Filter filter) {
SearchCriteria<ClusterVO> sc = ZoneHyTypeSearch.create();
sc.setParameters("hypervisorType", hypervisorType.toString());
return listBy(sc);
return listBy(sc, filter);
}
}

View File

@ -24,6 +24,7 @@ import com.cloud.network.Network;
import com.cloud.network.Network.GuestType;
import com.cloud.network.Network.State;
import com.cloud.network.Networks.TrafficType;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDao;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.fsm.StateDao;
@ -96,9 +97,11 @@ public interface NetworkDao extends GenericDao<NetworkVO, Long>, StateDao<State,
boolean update(Long networkId, NetworkVO network, Map<String, String> serviceProviderMap);
List<NetworkVO> listByZoneAndTrafficType(long zoneId, TrafficType trafficType, Filter filter);
List<NetworkVO> listByZoneAndTrafficType(long zoneId, TrafficType trafficType);
List<NetworkVO> listByTrafficType(TrafficType trafficType);
List<NetworkVO> listByTrafficType(TrafficType trafficType, Filter filter);
void setCheckForGc(long networkId);

View File

@ -632,20 +632,25 @@ public class NetworkDaoImpl extends GenericDaoBase<NetworkVO, Long>implements Ne
}
@Override
public List<NetworkVO> listByZoneAndTrafficType(final long zoneId, final TrafficType trafficType) {
public List<NetworkVO> listByZoneAndTrafficType(final long zoneId, final TrafficType trafficType, Filter filter) {
final SearchCriteria<NetworkVO> sc = AllFieldsSearch.create();
sc.setParameters("datacenter", zoneId);
sc.setParameters("trafficType", trafficType);
return listBy(sc, null);
return listBy(sc, filter);
}
@Override
public List<NetworkVO> listByTrafficType(final TrafficType trafficType) {
public List<NetworkVO> listByZoneAndTrafficType(final long zoneId, final TrafficType trafficType) {
return listByZoneAndTrafficType(zoneId, trafficType, null);
}
@Override
public List<NetworkVO> listByTrafficType(final TrafficType trafficType, Filter filter) {
final SearchCriteria<NetworkVO> sc = AllFieldsSearch.create();
sc.setParameters("trafficType", trafficType);
return listBy(sc, null);
return listBy(sc, filter);
}
@Override

View File

@ -23,6 +23,7 @@ import java.util.Set;
import com.cloud.server.ResourceTag;
import com.cloud.server.ResourceTag.ResourceObjectType;
import com.cloud.tags.ResourceTagVO;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDao;
import org.apache.cloudstack.api.response.ResourceTagResponse;
@ -61,5 +62,5 @@ public interface ResourceTagDao extends GenericDao<ResourceTagVO, Long> {
List<? extends ResourceTag> listByResourceUuid(String resourceUuid);
List<ResourceTagVO> listByResourceType(ResourceObjectType resourceType);
List<ResourceTagVO> listByResourceType(ResourceObjectType resourceType, Filter filter);
}

View File

@ -28,6 +28,7 @@ import org.springframework.stereotype.Component;
import com.cloud.server.ResourceTag;
import com.cloud.server.ResourceTag.ResourceObjectType;
import com.cloud.tags.ResourceTagVO;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
@ -122,9 +123,9 @@ public class ResourceTagsDaoImpl extends GenericDaoBase<ResourceTagVO, Long> imp
}
@Override
public List<ResourceTagVO> listByResourceType(ResourceObjectType resourceType) {
public List<ResourceTagVO> listByResourceType(ResourceObjectType resourceType, Filter filter) {
SearchCriteria<ResourceTagVO> sc = AllFieldsSearch.create();
sc.setParameters("resourceType", resourceType);
return listBy(sc);
return listBy(sc, filter);
}
}

View File

@ -19,7 +19,7 @@ package org.apache.cloudstack.veeam;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Map;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -30,6 +30,7 @@ import org.apache.logging.log4j.Logger;
import com.cloud.utils.component.Adapter;
public interface RouteHandler extends Adapter {
static final Pattern PAGE_PATTERN = Pattern.compile("\\bpage\\s+(\\d+)");
default int priority() { return 0; }
boolean canHandle(String method, String path) throws IOException;
void handle(HttpServletRequest req, HttpServletResponse resp, String path, Negotiation.OutFormat outFormat, VeeamControlServlet io)
@ -73,10 +74,4 @@ public interface RouteHandler extends Adapter {
return null;
}
}
static Map<String, String> getRequestParams(HttpServletRequest req) {
return req.getParameterMap().entrySet().stream()
.filter(e -> e.getValue() != null && e.getValue().length > 0)
.collect(java.util.stream.Collectors.toMap(Map.Entry::getKey, e -> e.getValue()[0]));
}
}

View File

@ -36,6 +36,9 @@ import org.apache.cloudstack.acl.RolePermissionEntity;
import org.apache.cloudstack.acl.RoleService;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.acl.Rule;
import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.affinity.AffinityGroupVO;
import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiServerService;
import org.apache.cloudstack.api.BaseCmd;
@ -116,20 +119,19 @@ import org.apache.cloudstack.veeam.api.dto.Vm;
import org.apache.cloudstack.veeam.api.dto.VmAction;
import org.apache.cloudstack.veeam.api.dto.VnicProfile;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import com.cloud.api.query.dao.AsyncJobJoinDao;
import com.cloud.api.query.dao.DataCenterJoinDao;
import com.cloud.api.query.dao.HostJoinDao;
import com.cloud.api.query.dao.ImageStoreJoinDao;
import com.cloud.api.query.dao.StoragePoolJoinDao;
import com.cloud.api.query.dao.UserVmJoinDao;
import com.cloud.api.query.dao.VolumeJoinDao;
import com.cloud.api.query.vo.AsyncJobJoinVO;
import com.cloud.api.query.vo.DataCenterJoinVO;
import com.cloud.api.query.vo.HostJoinVO;
import com.cloud.api.query.vo.ImageStoreJoinVO;
import com.cloud.api.query.vo.StoragePoolJoinVO;
import com.cloud.api.query.vo.UserVmJoinVO;
import com.cloud.api.query.vo.VolumeJoinVO;
@ -152,6 +154,7 @@ import com.cloud.org.Grouping;
import com.cloud.projects.Project;
import com.cloud.projects.ProjectService;
import com.cloud.server.ResourceTag;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Volume;
@ -166,15 +169,18 @@ import com.cloud.user.Account;
import com.cloud.user.AccountService;
import com.cloud.user.User;
import com.cloud.user.UserAccount;
import com.cloud.user.UserDataVO;
import com.cloud.user.dao.UserDataDao;
import com.cloud.uservm.UserVm;
import com.cloud.utils.EnumUtils;
import com.cloud.utils.Pair;
import com.cloud.utils.Ternary;
import com.cloud.utils.component.ComponentContext;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.db.Filter;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.NicVO;
import com.cloud.vm.UserVmService;
import com.cloud.vm.UserVmManager;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VmDetailConstants;
import com.cloud.vm.dao.NicDao;
@ -183,8 +189,7 @@ import com.cloud.vm.dao.VMInstanceDetailsDao;
import com.cloud.vm.snapshot.VMSnapshotVO;
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
// ToDo: fix list APIs to support pagination, etc
// ToDo: check access on objects
// ToDo: check access for list APIs when not ROOT admin
public class ServerAdapter extends ManagerBase {
private static final String SERVICE_ACCOUNT_NAME = "veemserviceuser";
@ -206,7 +211,7 @@ public class ServerAdapter extends ManagerBase {
ResizeVolumeCmd.class,
ListNetworksCmd.class
);
public static final String GUEST_CPU_MODE = "host-passthrough";
public static final String WORKER_VM_GUEST_CPU_MODE = "host-passthrough";
@Inject
RoleService roleService;
@ -223,9 +228,6 @@ public class ServerAdapter extends ManagerBase {
@Inject
StoragePoolJoinDao storagePoolJoinDao;
@Inject
ImageStoreJoinDao imageStoreJoinDao;
@Inject
ClusterDao clusterDao;
@ -275,7 +277,7 @@ public class ServerAdapter extends ManagerBase {
VMTemplateDao templateDao;
@Inject
UserVmService userVmService;
UserVmManager userVmManager;
@Inject
NicDao nicDao;
@ -304,6 +306,12 @@ public class ServerAdapter extends ManagerBase {
@Inject
ProjectService projectService;
@Inject
AffinityGroupDao affinityGroupDao;
@Inject
UserDataDao userDataDao;
protected static Tag getDummyTagByName(String name) {
Tag tag = new Tag();
String id = UUID.nameUUIDFromBytes(String.format("veeam:%s", name.toLowerCase()).getBytes()).toString();
@ -429,15 +437,22 @@ public class ServerAdapter extends ManagerBase {
waitForJobCompletion(job.getId());
}
protected void validateServiceAccountAdminAccess() {
Pair<User, Account> serviceAccount = getServiceAccount();
if (!accountService.isAdmin(serviceAccount.second().getId())) {
throw new InvalidParameterValueException("Service account does not have access");
}
}
@Override
public boolean start() {
getServiceAccount();
//find public custom disk offering
return true;
}
public List<DataCenter> listAllDataCenters() {
final List<DataCenterJoinVO> clusters = dataCenterJoinDao.listAll();
public List<DataCenter> listAllDataCenters(Long offset, Long limit) {
Filter filter = new Filter(DataCenterJoinVO.class, "id", true, offset, limit);
final List<DataCenterJoinVO> clusters = dataCenterJoinDao.listAll(filter);
return DataCenterJoinVOToDataCenterConverter.toDCList(clusters);
}
@ -449,81 +464,92 @@ public class ServerAdapter extends ManagerBase {
return DataCenterJoinVOToDataCenterConverter.toDataCenter(vo);
}
public List<StorageDomain> listStorageDomainsByDcId(final String uuid) {
final DataCenterJoinVO dataCenterVO = dataCenterJoinDao.findByUuid(uuid);
public List<StorageDomain> listStorageDomainsByDcId(final String uuid, final Long offset, final Long limit) {
final DataCenterVO dataCenterVO = dataCenterDao.findByUuid(uuid);
if (dataCenterVO == null) {
throw new InvalidParameterValueException("DataCenter with ID " + uuid + " not found");
}
List<StoragePoolJoinVO> storagePoolVOS = storagePoolJoinDao.listAll();
List<StorageDomain> storageDomains = StoreVOToStorageDomainConverter.toStorageDomainListFromPools(storagePoolVOS);
List<ImageStoreJoinVO> imageStoreJoinVOS = imageStoreJoinDao.listAll();
storageDomains.addAll(StoreVOToStorageDomainConverter.toStorageDomainListFromStores(imageStoreJoinVOS));
return storageDomains;
validateServiceAccountAdminAccess();
Filter filter = new Filter(StoragePoolJoinVO.class, "id", true, offset, limit);
List<StoragePoolJoinVO> storagePoolVOS = storagePoolJoinDao.listByZoneAndProvider(dataCenterVO.getId(), filter);
return StoreVOToStorageDomainConverter.toStorageDomainListFromPools(storagePoolVOS);
}
public List<Network> listNetworksByDcId(final String uuid) {
public List<Network> listNetworksByDcId(final String uuid, final Long offset, final Long limit) {
final DataCenterJoinVO dataCenterVO = dataCenterJoinDao.findByUuid(uuid);
if (dataCenterVO == null) {
throw new InvalidParameterValueException("DataCenter with ID " + uuid + " not found");
}
List<NetworkVO> networks = networkDao.listByZoneAndTrafficType(dataCenterVO.getId(), Networks.TrafficType.Guest);
validateServiceAccountAdminAccess();
Filter filter = new Filter(NetworkVO.class, "id", true, offset, limit);
List<NetworkVO> networks = networkDao.listByZoneAndTrafficType(dataCenterVO.getId(), Networks.TrafficType.Guest, filter);
return NetworkVOToNetworkConverter.toNetworkList(networks, (dcId) -> dataCenterVO);
}
public List<Cluster> listAllClusters() {
final List<ClusterVO> clusters = clusterDao.listByHypervisorType(Hypervisor.HypervisorType.KVM);
public List<Cluster> listAllClusters(Long offset, Long limit) {
validateServiceAccountAdminAccess();
Filter filter = new Filter(ClusterVO.class, "id", true, offset, limit);
final List<ClusterVO> clusters = clusterDao.listByHypervisorType(Hypervisor.HypervisorType.KVM, filter);
return ClusterVOToClusterConverter.toClusterList(clusters, this::getZoneById);
}
public Cluster getCluster(String uuid) {
validateServiceAccountAdminAccess();
final ClusterVO vo = clusterDao.findByUuid(uuid);
if (vo == null) {
throw new InvalidParameterValueException("Cluster with ID " + uuid + " not found");
}
return ClusterVOToClusterConverter.toCluster(vo, this::getZoneById);
return ClusterVOToClusterConverter.toCluster(vo, this::getZoneById);
}
public List<Host> listAllHosts() {
final List<HostJoinVO> hosts = hostJoinDao.listRoutingHostsByHypervisor(Hypervisor.HypervisorType.KVM);
public List<Host> listAllHosts(Long offset, Long limit) {
validateServiceAccountAdminAccess();
Filter filter = new Filter(HostJoinVO.class, "id", true, offset, limit);
final List<HostJoinVO> hosts = hostJoinDao.listRoutingHostsByHypervisor(Hypervisor.HypervisorType.KVM, filter);
return HostJoinVOToHostConverter.toHostList(hosts);
}
public Host getHost(String uuid) {
validateServiceAccountAdminAccess();
final HostJoinVO vo = hostJoinDao.findByUuid(uuid);
if (vo == null) {
throw new InvalidParameterValueException("Host with ID " + uuid + " not found");
}
return HostJoinVOToHostConverter.toHost(vo);
return HostJoinVOToHostConverter.toHost(vo);
}
public List<Network> listAllNetworks() {
final List<NetworkVO> networks = networkDao.listAll();
public List<Network> listAllNetworks(Long offset, Long limit) {
Filter filter = new Filter(NetworkVO.class, "id", true, offset, limit);
final List<NetworkVO> networks = networkDao.listByTrafficType(Networks.TrafficType.Guest, filter);
return NetworkVOToNetworkConverter.toNetworkList(networks, this::getZoneById);
}
public Network getNetwork(String uuid) {
final NetworkVO vo = networkDao.findByUuid(uuid);
if (vo == null) {
throw new InvalidParameterValueException("Host with ID " + uuid + " not found");
throw new InvalidParameterValueException("Network with ID " + uuid + " not found");
}
accountService.checkAccess(getServiceAccount().second(), null, false, vo);
return NetworkVOToNetworkConverter.toNetwork(vo, this::getZoneById);
}
public List<VnicProfile> listAllVnicProfiles() {
final List<NetworkVO> networks = networkDao.listByTrafficType(Networks.TrafficType.Guest);
public List<VnicProfile> listAllVnicProfiles(Long offset, Long limit) {
Filter filter = new Filter(NetworkVO.class, "id", true, offset, limit);
final List<NetworkVO> networks = networkDao.listByTrafficType(Networks.TrafficType.Guest, filter);
return NetworkVOToVnicProfileConverter.toVnicProfileList(networks, this::getZoneById);
}
public VnicProfile getVnicProfile(String uuid) {
final NetworkVO vo = networkDao.findByUuid(uuid);
if (vo == null) {
throw new InvalidParameterValueException("Host with ID " + uuid + " not found");
throw new InvalidParameterValueException("Nic profile with ID " + uuid + " not found");
}
return NetworkVOToVnicProfileConverter.toVnicProfile(vo, this::getZoneById);
}
public List<Vm> listAllInstances() {
List<UserVmJoinVO> vms = userVmJoinDao.listByHypervisorType(Hypervisor.HypervisorType.KVM);
public List<Vm> listAllInstances(Long offset, Long limit) {
Filter filter = new Filter(UserVmJoinVO.class, "id", true, offset, limit);
List<UserVmJoinVO> vms = userVmJoinDao.listByHypervisorType(Hypervisor.HypervisorType.KVM, filter);
return UserVmJoinVOToVmConverter.toVmList(vms, this::getHostById, this::getDetailsByInstanceId);
}
@ -539,17 +565,24 @@ public class ServerAdapter extends ManagerBase {
allContent);
}
Ternary<Long, String, Long> getVmOwner(Vm request) {
Account getOwnerForInstanceCreation(Vm request) {
if (!VeeamControlService.InstanceRestoreAssignOwner.value()) {
return new Ternary<>(null, null, null);
return null;
}
String accountUuid = request.getAccountId();
if (StringUtils.isBlank(accountUuid)) {
return new Ternary<>(null, null, null);
return null;
}
Account account = accountService.getActiveAccountByUuid(accountUuid);
if (account == null) {
logger.warn("Account with ID {} not found, unable to determine owner for VM creation request", accountUuid);
return null;
}
return account;
}
Ternary<Long, String, Long> getOwnerDetailsForInstanceCreation(Account account) {
if (account == null) {
return new Ternary<>(null, null, null);
}
String accountName = account.getAccountName();
@ -576,7 +609,7 @@ public class ServerAdapter extends ManagerBase {
throw new InvalidParameterValueException("Invalid name specified for the VM");
}
String displayName = name;
name = name.replaceAll("_", "-");
name = name.replace("_", "-");
Long zoneId = null;
Long clusterId = null;
if (request.getCluster() != null && StringUtils.isNotEmpty(request.getCluster().getId())) {
@ -589,6 +622,10 @@ public class ServerAdapter extends ManagerBase {
if (zoneId == null) {
throw new InvalidParameterValueException("Failed to determine datacenter for VM creation request");
}
DataCenterVO zone = dataCenterDao.findById(zoneId);
if (zone == null) {
throw new InvalidParameterValueException("DataCenter could not be determined for the request");
}
Integer cpu = null;
try {
cpu = Integer.valueOf(request.getCpu().getTopology().getSockets());
@ -605,12 +642,14 @@ public class ServerAdapter extends ManagerBase {
if (memory == null) {
throw new InvalidParameterValueException("Memory must be specified");
}
int memoryMB = (int)(memory / (1024L * 1024L));
String userdata = null;
if (request.getInitialization() != null) {
userdata = request.getInitialization().getCustomScript();
}
Pair<ApiConstants.BootType, ApiConstants.BootMode> bootOptions = Vm.Bios.retrieveBootOptions(request.getBios());
Ternary<Long, String, Long> owner = getVmOwner(request);
Account owner = getOwnerForInstanceCreation(request);
Ternary<Long, String, Long> ownerDetails = getOwnerDetailsForInstanceCreation(owner);
String serviceOfferingUuid = null;
if (request.getCpuProfile() != null && StringUtils.isNotEmpty(request.getCpuProfile().getId())) {
serviceOfferingUuid = request.getCpuProfile().getId();
@ -620,29 +659,68 @@ public class ServerAdapter extends ManagerBase {
templateUuid = request.getTemplate().getId();
}
Pair<User, Account> serviceUserAccount = getServiceAccount();
CallContext ctx = CallContext.register(serviceUserAccount.first(), serviceUserAccount.second());
CallContext.register(serviceUserAccount.first(), serviceUserAccount.second());
try {
return createInstance(zoneId, clusterId, owner.first(), owner.second(), owner.third(), name, displayName,
serviceOfferingUuid, cpu, memory, templateUuid, userdata, bootOptions.first(), bootOptions.second());
return createInstance(zone, clusterId, owner, ownerDetails.first(), ownerDetails.second(),
ownerDetails.third(), name, displayName, serviceOfferingUuid, cpu, memoryMB, templateUuid,
userdata, bootOptions.first(), bootOptions.second(), request.getAffinityGroupId(),
request.getUserDataId(), request.getDetails());
} finally {
CallContext.unregister();
}
}
protected ServiceOffering getServiceOfferingIdForVmCreation(String serviceOfferingUuid, long zoneId, int cpu, long memory) {
if (StringUtils.isNotBlank(serviceOfferingUuid)) {
ServiceOffering offering = serviceOfferingDao.findByUuid(serviceOfferingUuid);
if (offering != null && !offering.isCustomized()) {
// ToDo: check offering is available in the specified zone and matches the requested cpu/memory if it's not a custom offering
return offering;
protected ServiceOffering getServiceOfferingFromRequest(com.cloud.dc.DataCenter zone, Account account,
String uuid, int cpu, int memory) {
if (StringUtils.isBlank(uuid)) {
return null;
}
ServiceOfferingVO offering = serviceOfferingDao.findByUuid(uuid);
if (offering == null) {
logger.warn("Service offering with ID {} linked with the VM request not found", uuid);
return null;
}
try {
accountService.checkAccess(account, offering, zone);
} catch (PermissionDeniedException e) {
logger.warn("Service offering with ID {} linked with the VM request is not accessible for the account {}. Offering: {}, zone: {}",
uuid, account, offering, zone);
return null;
}
if (!offering.isCustomized() && (offering.getCpu() != cpu || offering.getRamSize() != memory)) {
logger.warn("Service offering with ID {} linked with the VM request has different CPU or memory than requested. Offering: {}, requested CPU: {}, requested memory: {}",
uuid, offering, cpu, memory);
return null;
}
if (offering.isCustomized()) {
Map<String, String> params = Map.of(
VmDetailConstants.CPU_NUMBER, String.valueOf(cpu),
VmDetailConstants.MEMORY, String.valueOf(memory)
);
try {
userVmManager.validateCustomParameters(offering, params);
offering.setCpu(cpu);
offering.setRamSize(memory);
} catch (InvalidParameterValueException e) {
logger.warn("Service offering with ID {} linked with the VM request is customized but does not support requested CPU or memory. Offering: {}, requested CPU: {}, requested memory: {}",
uuid, offering, cpu, memory);
return null;
}
}
return offering;
}
protected ServiceOffering getServiceOfferingIdForVmCreation(com.cloud.dc.DataCenter zone, Account account,
String serviceOfferingUuid, int cpu, int memory) {
ServiceOffering offering = getServiceOfferingFromRequest(zone, account, serviceOfferingUuid, cpu, memory);
if (offering != null) {
return offering;
}
ListServiceOfferingsCmd cmd = new ListServiceOfferingsCmd();
ComponentContext.inject(cmd);
cmd.setZoneId(zoneId);
cmd.setZoneId(zone.getId());
cmd.setCpuNumber(cpu);
Integer memoryMB = (int)(memory / (1024L * 1024L));
cmd.setMemory(memoryMB);
cmd.setMemory(memory);
ListResponse<ServiceOfferingResponse> offerings = queryService.searchForServiceOfferings(cmd);
if (offerings.getResponses().isEmpty()) {
return null;
@ -651,7 +729,7 @@ public class ServerAdapter extends ManagerBase {
return serviceOfferingDao.findByUuid(uuid);
}
protected VMTemplateVO getTemplateForVmCreation(String templateUuid) {
protected VMTemplateVO getTemplateForInstanceCreation(String templateUuid) {
if (StringUtils.isBlank(templateUuid)) {
return null;
}
@ -663,17 +741,20 @@ public class ServerAdapter extends ManagerBase {
return template;
}
protected Vm createInstance(Long zoneId, Long clusterId, Long domainId, String accountName, Long projectId,
String name, String displayName, String serviceOfferingUuid, int cpu, long memory, String templateUuid,
String userdata, ApiConstants.BootType bootType, ApiConstants.BootMode bootMode) {
ServiceOffering serviceOffering = getServiceOfferingIdForVmCreation(serviceOfferingUuid, zoneId, cpu, memory);
protected Vm createInstance(com.cloud.dc.DataCenter zone, Long clusterId, Account owner, Long domainId,
String accountName, Long projectId, String name, String displayName, String serviceOfferingUuid,
int cpu, int memory, String templateUuid, String userdata, ApiConstants.BootType bootType,
ApiConstants.BootMode bootMode, String affinityGroupId, String userDataId, Map<String, String> details) {
Account account = owner != null ? owner : CallContext.current().getCallingAccount();
ServiceOffering serviceOffering = getServiceOfferingIdForVmCreation(zone, account, serviceOfferingUuid, cpu,
memory);
if (serviceOffering == null) {
throw new CloudRuntimeException("No service offering found for VM creation with specified CPU and memory");
}
DeployVMCmdByAdmin cmd = new DeployVMCmdByAdmin();
cmd.setHttpMethod(BaseCmd.HTTPMethod.POST.name());
ComponentContext.inject(cmd);
cmd.setZoneId(zoneId);
cmd.setZoneId(zone.getId());
cmd.setClusterId(clusterId);
if (domainId != null && StringUtils.isNotEmpty(accountName)) {
cmd.setDomainId(domainId);
@ -696,22 +777,39 @@ public class ServerAdapter extends ManagerBase {
if (bootMode != null) {
cmd.setBootMode(bootMode.toString());
}
VMTemplateVO template = getTemplateForVmCreation(templateUuid);
VMTemplateVO template = getTemplateForInstanceCreation(templateUuid);
if (template != null) {
cmd.setTemplateId(template.getId());
}
// ToDo: handle any other field?
// Handle custom offerings
if (StringUtils.isNotBlank(affinityGroupId)) {
AffinityGroupVO group = affinityGroupDao.findByUuid(affinityGroupId);
if (group == null) {
logger.warn("Failed to find affinity group with ID {} specified in Instance creation request, " +
"skipping affinity group assignment", affinityGroupId);
} else {
cmd.setAffinityGroupIds(List.of(group.getId()));
}
}
if (StringUtils.isNotBlank(userDataId)) {
UserDataVO userData = userDataDao.findByUuid(userDataId);
if (userData == null) {
logger.warn("Failed to find userdata with ID {} specified in Instance creation request, " +
"skipping userdata assignment", userDataId);
} else {
cmd.setUserDataId(userData.getId());
}
}
cmd.setHypervisor(Hypervisor.HypervisorType.KVM.name());
Map<String, String> instanceDetails = getDetailsForInstanceCreation(userdata, serviceOffering, details);
if (MapUtils.isNotEmpty(instanceDetails)) {
Map<Integer, Map<String, String>> map = new HashMap<>();
map.put(0, details);
cmd.setDetails(map);
}
cmd.setBlankInstance(true);
Map<String, String> details = new HashMap<>();
details.put(VmDetailConstants.GUEST_CPU_MODE, GUEST_CPU_MODE);
Map<Integer, Map<String, String>> map = new HashMap<>();
map.put(0, details);
cmd.setDetails(map);
try {
UserVm vm = userVmService.createVirtualMachine(cmd);
vm = userVmService.finalizeCreateVirtualMachine(vm.getId());
UserVm vm = userVmManager.createVirtualMachine(cmd);
vm = userVmManager.finalizeCreateVirtualMachine(vm.getId());
UserVmJoinVO vo = userVmJoinDao.findById(vm.getId());
return UserVmJoinVOToVmConverter.toVm(vo, this::getHostById, this::getDetailsByInstanceId,
this::listDiskAttachmentsByInstanceId, this::listNicsByInstance, false);
@ -720,6 +818,35 @@ public class ServerAdapter extends ManagerBase {
}
}
@NotNull
private static Map<String, String> getDetailsForInstanceCreation(String userdata, ServiceOffering serviceOffering,
Map<String, String> existingDetails) {
Map<String, String> details = new HashMap<>();
List<String> detailsTobeSkipped = List.of(
ApiConstants.BootType.BIOS.toString(),
ApiConstants.BootType.UEFI.toString());
if (MapUtils.isNotEmpty(existingDetails)) {
for (Map.Entry<String, String> entry : existingDetails.entrySet()) {
if (detailsTobeSkipped.contains(entry.getKey())) {
continue;
}
details.put(entry.getKey(), entry.getValue());
}
}
if (StringUtils.isNotEmpty(userdata)) {
// Assumption: Only worker VM will have userdata and it needs CPU mode
details.put(VmDetailConstants.GUEST_CPU_MODE, WORKER_VM_GUEST_CPU_MODE);
}
if (serviceOffering.isCustomized()) {
details.put(VmDetailConstants.CPU_NUMBER, String.valueOf(serviceOffering.getCpu()));
details.put(VmDetailConstants.MEMORY, String.valueOf(serviceOffering.getRamSize()));
if (serviceOffering.getSpeed() == null && !details.containsKey(VmDetailConstants.CPU_SPEED)) {
details.put(VmDetailConstants.CPU_SPEED, String.valueOf(1000));
}
}
return details;
}
public Vm updateInstance(String uuid, Vm request) {
logger.warn("Received request to update VM with ID {}. No action, returning existing VM data.", uuid);
return getInstance(uuid, false, false, false);
@ -856,51 +983,27 @@ public class ServerAdapter extends ManagerBase {
return volumeApiService.getVolumePhysicalSize(vo.getFormat(), vo.getPath(), vo.getChainInfo());
}
public List<Disk> listAllDisks() {
List<VolumeJoinVO> kvmVolumes = volumeJoinDao.listByHypervisor(Hypervisor.HypervisorType.KVM);
public List<Disk> listAllDisks(Long offset, Long limit) {
Filter filter = new Filter(VolumeJoinVO.class, "id", true, offset, limit);
List<VolumeJoinVO> kvmVolumes = volumeJoinDao.listByHypervisor(Hypervisor.HypervisorType.KVM, filter);
return VolumeJoinVOToDiskConverter.toDiskList(kvmVolumes, this::getVolumePhysicalSize);
}
public Disk getDisk(String uuid) {
VolumeJoinVO vo = volumeJoinDao.findByUuid(uuid);
VolumeVO vo = volumeDao.findByUuid(uuid);
if (vo == null) {
throw new InvalidParameterValueException("Disk with ID " + uuid + " not found");
}
return VolumeJoinVOToDiskConverter.toDisk(vo, this::getVolumePhysicalSize);
accountService.checkAccess(getServiceAccount().second(), null, false, vo);
return VolumeJoinVOToDiskConverter.toDisk(volumeJoinDao.findByUuid(uuid), this::getVolumePhysicalSize);
}
public Disk copyDisk(String uuid) {
throw new InvalidParameterValueException("Copy Disk with ID " + uuid + " not implemented");
// VolumeVO vo = volumeDao.findByUuid(uuid);
// if (vo == null) {
// throw new InvalidParameterValueException("Disk with ID " + uuid + " not found");
// }
// Pair<User, Account> serviceUserAccount = createServiceAccountIfNeeded();
// CallContext.register(serviceUserAccount.first(), serviceUserAccount.second());
// try {
// Volume volume = volumeApiService.copyVolume(vo.getId(), vo.getName() + "_copy", null, null);
// VolumeJoinVO copiedVolumeVO = volumeJoinDao.findById(volume.getId());
// return VolumeJoinVOToDiskConverter.toDisk(copiedVolumeVO);
// } finally {
// CallContext.unregister();
// }
}
public Disk reduceDisk(String uuid) {
throw new InvalidParameterValueException("Reduce Disk with ID " + uuid + " not implemented");
// VolumeVO vo = volumeDao.findByUuid(uuid);
// if (vo == null) {
// throw new InvalidParameterValueException("Disk with ID " + uuid + " not found");
// }
// Pair<User, Account> serviceUserAccount = createServiceAccountIfNeeded();
// CallContext.register(serviceUserAccount.first(), serviceUserAccount.second());
// try {
// Volume volume = volumeApiService.reduceDisk(vo.getId(), vo.getName() + "_copy", null, null);
// VolumeJoinVO copiedVolumeVO = volumeJoinDao.findById(volume.getId());
// return VolumeJoinVOToDiskConverter.toDisk(copiedVolumeVO);
// } finally {
// CallContext.unregister();
// }
}
protected List<DiskAttachment> listDiskAttachmentsByInstanceId(final long instanceId) {
@ -913,6 +1016,7 @@ public class ServerAdapter extends ManagerBase {
if (vo == null) {
throw new InvalidParameterValueException("VM with ID " + uuid + " not found");
}
accountService.checkAccess(getServiceAccount().second(), null, false, vo);
return listDiskAttachmentsByInstanceId(vo.getId());
}
@ -953,6 +1057,8 @@ public class ServerAdapter extends ManagerBase {
if (vmVo == null) {
throw new InvalidParameterValueException("VM with ID " + vmUuid + " not found");
}
Pair<User, Account> serviceUserAccount = getServiceAccount();
accountService.checkAccess(serviceUserAccount.second(), SecurityChecker.AccessType.OperateEntry, false, vmVo);
if (request == null || request.getDisk() == null || StringUtils.isEmpty(request.getDisk().getId())) {
throw new InvalidParameterValueException("Request disk data is empty");
}
@ -960,7 +1066,7 @@ public class ServerAdapter extends ManagerBase {
if (volumeVO == null) {
throw new InvalidParameterValueException("Disk with ID " + request.getDisk().getId() + " not found");
}
Pair<User, Account> serviceUserAccount = getServiceAccount();
accountService.checkAccess(serviceUserAccount.second(), SecurityChecker.AccessType.OperateEntry, false, vmVo);
if (vmVo.getAccountId() != volumeVO.getAccountId()) {
if (VeeamControlService.InstanceRestoreAssignOwner.value()) {
assignVolumeToAccount(volumeVO, vmVo.getAccountId(), serviceUserAccount);
@ -1013,18 +1119,7 @@ public class ServerAdapter extends ManagerBase {
if (StringUtils.isBlank(sizeStr)) {
throw new InvalidParameterValueException("Provisioned size must be specified");
}
long provisionedSizeInGb;
try {
provisionedSizeInGb = Long.parseLong(sizeStr);
} catch (NumberFormatException ex) {
throw new InvalidParameterValueException("Invalid provisioned size: " + sizeStr);
}
if (provisionedSizeInGb <= 0) {
throw new InvalidParameterValueException("Provisioned size must be greater than zero");
}
// round-up provisionedSizeInGb to the next whole GB
long GB = 1024L * 1024L * 1024L;
provisionedSizeInGb = Math.max(1L, (provisionedSizeInGb + GB - 1) / GB);
long provisionedSizeInGb = getProvisionedSizeInGb(sizeStr);
Long initialSize = null;
if (StringUtils.isNotBlank(request.getInitialSize())) {
try {
@ -1049,6 +1144,22 @@ public class ServerAdapter extends ManagerBase {
}
}
private static long getProvisionedSizeInGb(String sizeStr) {
long provisionedSizeInGb;
try {
provisionedSizeInGb = Long.parseLong(sizeStr);
} catch (NumberFormatException ex) {
throw new InvalidParameterValueException("Invalid provisioned size: " + sizeStr);
}
if (provisionedSizeInGb <= 0) {
throw new InvalidParameterValueException("Provisioned size must be greater than zero");
}
// round-up provisionedSizeInGb to the next whole GB
long GB = 1024L * 1024L * 1024L;
provisionedSizeInGb = Math.max(1L, (provisionedSizeInGb + GB - 1) / GB);
return provisionedSizeInGb;
}
@NotNull
private Disk createDisk(Account serviceAccount, StoragePoolVO pool, String name, Long diskOfferingId, long sizeInGb, Long initialSize) {
Volume volume;
@ -1084,6 +1195,7 @@ public class ServerAdapter extends ManagerBase {
if (vo == null) {
throw new InvalidParameterValueException("VM with ID " + uuid + " not found");
}
accountService.checkAccess(getServiceAccount().second(), null, false, vo);
return listNicsByInstance(vo.getId(), vo.getUuid());
}
@ -1119,7 +1231,7 @@ public class ServerAdapter extends ManagerBase {
cmd.setAccountName(account.getAccountName());
}
cmd.setSkipNetwork(true);
userVmService.moveVmToUser(cmd);
userVmManager.moveVmToUser(cmd);
} catch (ResourceAllocationException | CloudRuntimeException | ResourceUnavailableException |
InsufficientCapacityException e) {
logger.error("Failed to assign {} to {}: {}", vmVO, account, e.getMessage(), e);
@ -1133,6 +1245,8 @@ public class ServerAdapter extends ManagerBase {
if (vmVo == null) {
throw new InvalidParameterValueException("VM with ID " + vmUuid + " not found");
}
Pair<User, Account> serviceUserAccount = getServiceAccount();
accountService.checkAccess(serviceUserAccount.second(), SecurityChecker.AccessType.OperateEntry, false, vmVo);
if (request == null || request.getVnicProfile() == null || StringUtils.isEmpty(request.getVnicProfile().getId())) {
throw new InvalidParameterValueException("Request nic data is empty");
}
@ -1140,7 +1254,7 @@ public class ServerAdapter extends ManagerBase {
if (networkVO == null) {
throw new InvalidParameterValueException("VNic profile " + request.getVnicProfile().getId() + " not found");
}
Pair<User, Account> serviceUserAccount = getServiceAccount();
accountService.checkAccess(serviceUserAccount.second(), SecurityChecker.AccessType.OperateEntry, false, networkVO);
if (vmVo.getAccountId() != networkVO.getAccountId() &&
networkVO.getAccountId() != Account.ACCOUNT_ID_SYSTEM &&
VeeamControlService.InstanceRestoreAssignOwner.value() &&
@ -1156,7 +1270,7 @@ public class ServerAdapter extends ManagerBase {
if (request.getMac() != null && StringUtils.isNotBlank(request.getMac().getAddress())) {
cmd.setMacAddress(request.getMac().getAddress());
}
userVmService.addNicToVirtualMachine(cmd);
userVmManager.addNicToVirtualMachine(cmd);
NicVO nic = nicDao.findByInstanceIdAndNetworkIdIncludingRemoved(networkVO.getId(), vmVo.getId());
if (nic == null) {
throw new CloudRuntimeException("Failed to attach NIC to VM");
@ -1167,8 +1281,9 @@ public class ServerAdapter extends ManagerBase {
}
}
public List<ImageTransfer> listAllImageTransfers() {
List<ImageTransferVO> imageTransfers = imageTransferDao.listAll();
public List<ImageTransfer> listAllImageTransfers(Long offset, Long limit) {
Filter filter = new Filter(ImageTransferVO.class, "id", true, offset, limit);
List<ImageTransferVO> imageTransfers = imageTransferDao.listAll(filter);
return ImageTransferVOToImageTransferConverter.toImageTransferList(imageTransfers, this::getHostById, this::getVolumeById);
}
@ -1177,6 +1292,7 @@ public class ServerAdapter extends ManagerBase {
if (vo == null) {
throw new InvalidParameterValueException("Image transfer with ID " + uuid + " not found");
}
accountService.checkAccess(getServiceAccount().second(), null, false, vo);
return ImageTransferVOToImageTransferConverter.toImageTransfer(vo, this::getHostById, this::getVolumeById);
}
@ -1191,6 +1307,8 @@ public class ServerAdapter extends ManagerBase {
if (volumeVO == null) {
throw new InvalidParameterValueException("Disk with ID " + request.getDisk().getId() + " not found");
}
Pair<User, Account> serviceUserAccount = getServiceAccount();
accountService.checkAccess(serviceUserAccount.second(), null, false, volumeVO);
Direction direction = EnumUtils.fromString(Direction.class, request.getDirection());
if (direction == null) {
throw new InvalidParameterValueException("Invalid or missing direction");
@ -1204,7 +1322,7 @@ public class ServerAdapter extends ManagerBase {
}
backupId = backupVO.getId();
}
return createImageTransfer(backupId, volumeVO.getId(), direction, format);
return createImageTransfer(backupId, volumeVO.getId(), direction, format, serviceUserAccount);
}
public boolean cancelImageTransfer(String uuid) {
@ -1212,6 +1330,7 @@ public class ServerAdapter extends ManagerBase {
if (vo == null) {
throw new InvalidParameterValueException("Image transfer with ID " + uuid + " not found");
}
accountService.checkAccess(getServiceAccount().second(), SecurityChecker.AccessType.OperateEntry, false, vo);
return kvmBackupExportService.cancelImageTransfer(vo.getId());
}
@ -1220,11 +1339,12 @@ public class ServerAdapter extends ManagerBase {
if (vo == null) {
throw new InvalidParameterValueException("Image transfer with ID " + uuid + " not found");
}
accountService.checkAccess(getServiceAccount().second(), SecurityChecker.AccessType.OperateEntry, false, vo);
return kvmBackupExportService.finalizeImageTransfer(vo.getId());
}
private ImageTransfer createImageTransfer(Long backupId, Long volumeId, Direction direction, Format format) {
Pair<User, Account> serviceUserAccount = getServiceAccount();
private ImageTransfer createImageTransfer(Long backupId, Long volumeId, Direction direction, Format format,
Pair<User, Account> serviceUserAccount) {
CallContext.register(serviceUserAccount.first(), serviceUserAccount.second());
try {
org.apache.cloudstack.backup.ImageTransfer imageTransfer =
@ -1268,7 +1388,7 @@ public class ServerAdapter extends ManagerBase {
return vmInstanceDetailsDao.listDetailsKeyPairs(instanceId, true);
}
public List<Job> listAllJobs() {
public List<Job> listPendingJobs() {
Pair<User, Account> serviceUserAccount = getServiceAccount();
List<Long> jobIds = asyncJobDao.listPendingJobIdsForAccount(serviceUserAccount.second().getId());
List<AsyncJobJoinVO> jobJoinVOs = asyncJobJoinDao.listByIds(jobIds);
@ -1280,6 +1400,7 @@ public class ServerAdapter extends ManagerBase {
if (vo == null) {
throw new InvalidParameterValueException("Job with ID " + uuid + " not found");
}
accountService.checkAccess(getServiceAccount().second(), null, false, vo);
return AsyncJobJoinVOToJobConverter.toJob(vo);
}
@ -1298,6 +1419,7 @@ public class ServerAdapter extends ManagerBase {
throw new InvalidParameterValueException("VM with ID " + vmUuid + " not found");
}
Pair<User, Account> serviceUserAccount = getServiceAccount();
accountService.checkAccess(serviceUserAccount.second(), SecurityChecker.AccessType.OperateEntry, false, vmVo);
CallContext ctx = CallContext.register(serviceUserAccount.first(), serviceUserAccount.second());
try {
CreateVMSnapshotCmd cmd = new CreateVMSnapshotCmd();
@ -1329,6 +1451,7 @@ public class ServerAdapter extends ManagerBase {
if (vo == null) {
throw new InvalidParameterValueException("Snapshot with ID " + uuid + " not found");
}
accountService.checkAccess(getServiceAccount().second(), null, false, vo);
UserVmVO vm = userVmDao.findById(vo.getVmId());
return VmSnapshotVOToSnapshotConverter.toSnapshot(vo, vm.getUuid());
}
@ -1340,6 +1463,7 @@ public class ServerAdapter extends ManagerBase {
throw new InvalidParameterValueException("Snapshot with ID " + uuid + " not found");
}
Pair<User, Account> serviceUserAccount = getServiceAccount();
accountService.checkAccess(serviceUserAccount.second(), SecurityChecker.AccessType.OperateEntry, false, vo);
CallContext ctx = CallContext.register(serviceUserAccount.first(), serviceUserAccount.second());
try {
DeleteVMSnapshotCmd cmd = new DeleteVMSnapshotCmd();
@ -1372,6 +1496,7 @@ public class ServerAdapter extends ManagerBase {
throw new InvalidParameterValueException("Snapshot with ID " + uuid + " not found");
}
Pair<User, Account> serviceUserAccount = getServiceAccount();
accountService.checkAccess(serviceUserAccount.second(), SecurityChecker.AccessType.OperateEntry, false, vo);
CallContext ctx = CallContext.register(serviceUserAccount.first(), serviceUserAccount.second());
try {
RevertToVMSnapshotCmd cmd = new RevertToVMSnapshotCmd();
@ -1412,6 +1537,7 @@ public class ServerAdapter extends ManagerBase {
throw new InvalidParameterValueException("VM with ID " + vmUuid + " not found");
}
Pair<User, Account> serviceUserAccount = getServiceAccount();
accountService.checkAccess(serviceUserAccount.second(), SecurityChecker.AccessType.OperateEntry, false, vmVo);
CallContext ctx = CallContext.register(serviceUserAccount.first(), serviceUserAccount.second());
try {
StartBackupCmd cmd = new StartBackupCmd();
@ -1442,6 +1568,7 @@ public class ServerAdapter extends ManagerBase {
if (vo == null) {
throw new InvalidParameterValueException("Backup with ID " + uuid + " not found");
}
accountService.checkAccess(getServiceAccount().second(), null, false, vo);
return BackupVOToBackupConverter.toBackup(vo, id -> userVmDao.findById(id), this::getHostById,
this::getBackupDisks);
}
@ -1461,6 +1588,7 @@ public class ServerAdapter extends ManagerBase {
throw new InvalidParameterValueException("Backup with ID " + backupUuid + " not found");
}
Pair<User, Account> serviceUserAccount = getServiceAccount();
accountService.checkAccess(serviceUserAccount.second(), SecurityChecker.AccessType.OperateEntry, false, backup);
CallContext ctx = CallContext.register(serviceUserAccount.first(), serviceUserAccount.second());
try {
FinalizeBackupCmd cmd = new FinalizeBackupCmd();
@ -1495,6 +1623,7 @@ public class ServerAdapter extends ManagerBase {
if (vo == null) {
throw new InvalidParameterValueException("VM with ID " + uuid + " not found");
}
accountService.checkAccess(getServiceAccount().second(), null, false, vo);
Checkpoint checkpoint = UserVmVOToCheckpointConverter.toCheckpoint(vo);
if (checkpoint == null) {
return Collections.emptyList();
@ -1507,6 +1636,7 @@ public class ServerAdapter extends ManagerBase {
if (vo == null) {
throw new InvalidParameterValueException("VM with ID " + vmUuid + " not found");
}
accountService.checkAccess(getServiceAccount().second(), SecurityChecker.AccessType.OperateEntry, false, vo);
if (!Objects.equals(vo.getActiveCheckpointId(), checkpointId)) {
logger.warn("Checkpoint ID {} does not match active checkpoint for VM {}", checkpointId, vmUuid);
return;
@ -1525,9 +1655,11 @@ public class ServerAdapter extends ManagerBase {
}
}
public List<Tag> listAllTags() {
public List<Tag> listAllTags(final Long offset, final Long limit) {
List<Tag> tags = new ArrayList<>(getDummyTags().values());
List<ResourceTagVO> vmResourceTags = resourceTagDao.listByResourceType(ResourceTag.ResourceObjectType.UserVm);
Filter filter = new Filter(ResourceTagVO.class, "id", true, offset, limit);
List<ResourceTagVO> vmResourceTags = resourceTagDao.listByResourceType(ResourceTag.ResourceObjectType.UserVm,
filter);
if (CollectionUtils.isNotEmpty(vmResourceTags)) {
tags.addAll(ResourceTagVOToTagConverter.toTags(vmResourceTags));
}
@ -1541,6 +1673,7 @@ public class ServerAdapter extends ManagerBase {
Tag tag = getDummyTags().get(uuid);
if (tag == null) {
ResourceTagVO resourceTagVO = resourceTagDao.findByUuid(uuid);
accountService.checkAccess(getServiceAccount().second(), null, false, resourceTagVO);
if (resourceTagVO != null) {
tag = ResourceTagVOToTagConverter.toTag(resourceTagVO);
}

View File

@ -76,16 +76,12 @@ public class ApiService extends ManagerBase implements RouteHandler {
add(links, basePath + "/clusters?search={query}", "clusters/search");
add(links, basePath + "/datacenters", "datacenters");
add(links, basePath + "/datacenters?search={query}", "datacenters/search");
add(links, basePath + "/events", "events");
add(links, basePath + "/events;from={event_id}?search={query}", "events/search");
add(links, basePath + "/hosts", "hosts");
add(links, basePath + "/hosts?search={query}", "hosts/search");
add(links, basePath + "/networks", "networks");
add(links, basePath + "/networks?search={query}", "networks/search");
add(links, basePath + "/storagedomains", "storagedomains");
add(links, basePath + "/storagedomains?search={query}", "storagedomains/search");
add(links, basePath + "/templates", "templates");
add(links, basePath + "/templates?search={query}", "templates/search");
add(links, basePath + "/vms", "vms");
add(links, basePath + "/vms?search={query}", "vms/search");
add(links, basePath + "/disks", "disks");

View File

@ -29,11 +29,13 @@ import org.apache.cloudstack.veeam.VeeamControlServlet;
import org.apache.cloudstack.veeam.adapter.ServerAdapter;
import org.apache.cloudstack.veeam.api.dto.Cluster;
import org.apache.cloudstack.veeam.api.dto.NamedList;
import org.apache.cloudstack.veeam.api.request.ListQuery;
import org.apache.cloudstack.veeam.utils.Negotiation;
import org.apache.cloudstack.veeam.utils.PathUtil;
import org.apache.commons.collections.CollectionUtils;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.utils.component.ManagerBase;
public class ClustersRouteHandler extends ManagerBase implements RouteHandler {
@ -84,9 +86,14 @@ public class ClustersRouteHandler extends ManagerBase implements RouteHandler {
protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
final List<Cluster> result = serverAdapter.listAllClusters();
NamedList<Cluster> response = NamedList.of("cluster", result);
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
try {
ListQuery query = ListQuery.fromRequest(req);
final List<Cluster> result = serverAdapter.listAllClusters(query.getOffset(), query.getLimit());
NamedList<Cluster> response = NamedList.of("cluster", result);
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
} catch (PermissionDeniedException e) {
io.badRequest(resp, e.getMessage(), outFormat);
}
}
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
@ -96,6 +103,8 @@ public class ClustersRouteHandler extends ManagerBase implements RouteHandler {
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
} catch (InvalidParameterValueException e) {
io.notFound(resp, e.getMessage(), outFormat);
} catch (PermissionDeniedException e) {
io.badRequest(resp, e.getMessage(), outFormat);
}
}
}

View File

@ -31,11 +31,13 @@ import org.apache.cloudstack.veeam.api.dto.DataCenter;
import org.apache.cloudstack.veeam.api.dto.NamedList;
import org.apache.cloudstack.veeam.api.dto.Network;
import org.apache.cloudstack.veeam.api.dto.StorageDomain;
import org.apache.cloudstack.veeam.api.request.ListQuery;
import org.apache.cloudstack.veeam.utils.Negotiation;
import org.apache.cloudstack.veeam.utils.PathUtil;
import org.apache.commons.collections.CollectionUtils;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.utils.component.ManagerBase;
public class DataCentersRouteHandler extends ManagerBase implements RouteHandler {
@ -81,11 +83,11 @@ public class DataCentersRouteHandler extends ManagerBase implements RouteHandler
} else if (idAndSubPath.size() == 2) {
String subPath = idAndSubPath.get(1);
if ("storagedomains".equals(subPath)) {
handleGetStorageDomainsByDcId(id, resp, outFormat, io);
handleGetStorageDomainsByDcId(id, req, resp, outFormat, io);
return;
}
if ("networks".equals(subPath)) {
handleGetNetworksByDcId(id, resp, outFormat, io);
handleGetNetworksByDcId(id, req, resp, outFormat, io);
return;
}
}
@ -96,7 +98,8 @@ public class DataCentersRouteHandler extends ManagerBase implements RouteHandler
protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
final List<DataCenter> result = serverAdapter.listAllDataCenters();
ListQuery query = ListQuery.fromRequest(req);
final List<DataCenter> result = serverAdapter.listAllDataCenters(query.getOffset(), query.getLimit());
NamedList<DataCenter> response = NamedList.of("data_center", result);
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
}
@ -111,25 +114,35 @@ public class DataCentersRouteHandler extends ManagerBase implements RouteHandler
}
}
protected void handleGetStorageDomainsByDcId(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
final VeeamControlServlet io) throws IOException {
protected void handleGetStorageDomainsByDcId(final String id, final HttpServletRequest req,
final HttpServletResponse resp, final Negotiation.OutFormat outFormat, final VeeamControlServlet io)
throws IOException {
try {
List<StorageDomain> storageDomains = serverAdapter.listStorageDomainsByDcId(id);
ListQuery query = ListQuery.fromRequest(req);
List<StorageDomain> storageDomains = serverAdapter.listStorageDomainsByDcId(id, query.getPage(),
query.getMax());
NamedList<StorageDomain> response = NamedList.of("storage_domain", storageDomains);
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
} catch (InvalidParameterValueException e) {
io.notFound(resp, e.getMessage(), outFormat);
} catch (PermissionDeniedException e) {
io.badRequest(resp, e.getMessage(), outFormat);
}
}
protected void handleGetNetworksByDcId(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
final VeeamControlServlet io) throws IOException {
protected void handleGetNetworksByDcId(final String id, final HttpServletRequest req,
final HttpServletResponse resp, final Negotiation.OutFormat outFormat, final VeeamControlServlet io)
throws IOException {
try {
List<Network> networks = serverAdapter.listNetworksByDcId(id);
ListQuery query = ListQuery.fromRequest(req);
List<Network> networks = serverAdapter.listNetworksByDcId(id, query.getPage(),
query.getMax());
NamedList<Network> response = NamedList.of("network", networks);
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
} catch (InvalidParameterValueException e) {
io.notFound(resp, e.getMessage(), outFormat);
} catch (PermissionDeniedException e) {
io.badRequest(resp, e.getMessage(), outFormat);
}
}
}

View File

@ -29,6 +29,7 @@ import org.apache.cloudstack.veeam.VeeamControlServlet;
import org.apache.cloudstack.veeam.adapter.ServerAdapter;
import org.apache.cloudstack.veeam.api.dto.Disk;
import org.apache.cloudstack.veeam.api.dto.NamedList;
import org.apache.cloudstack.veeam.api.request.ListQuery;
import org.apache.cloudstack.veeam.utils.Negotiation;
import org.apache.cloudstack.veeam.utils.PathUtil;
import org.apache.commons.collections.CollectionUtils;
@ -120,7 +121,8 @@ public class DisksRouteHandler extends ManagerBase implements RouteHandler {
protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
final List<Disk> result = serverAdapter.listAllDisks();
ListQuery query = ListQuery.fromRequest(req);
final List<Disk> result = serverAdapter.listAllDisks(query.getOffset(), query.getLimit());
NamedList<Disk> response = NamedList.of("disk", result);
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
}

View File

@ -29,11 +29,13 @@ import org.apache.cloudstack.veeam.VeeamControlServlet;
import org.apache.cloudstack.veeam.adapter.ServerAdapter;
import org.apache.cloudstack.veeam.api.dto.Host;
import org.apache.cloudstack.veeam.api.dto.NamedList;
import org.apache.cloudstack.veeam.api.request.ListQuery;
import org.apache.cloudstack.veeam.utils.Negotiation;
import org.apache.cloudstack.veeam.utils.PathUtil;
import org.apache.commons.collections.CollectionUtils;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.utils.component.ManagerBase;
public class HostsRouteHandler extends ManagerBase implements RouteHandler {
@ -84,9 +86,14 @@ public class HostsRouteHandler extends ManagerBase implements RouteHandler {
protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
final List<Host> result = serverAdapter.listAllHosts();
NamedList<Host> response = NamedList.of("host", result);
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
try {
ListQuery query = ListQuery.fromRequest(req);
final List<Host> result = serverAdapter.listAllHosts(query.getOffset(), query.getLimit());
NamedList<Host> response = NamedList.of("host", result);
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
} catch (PermissionDeniedException e) {
io.badRequest(resp, e.getMessage(), outFormat);
}
}
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
@ -96,6 +103,8 @@ public class HostsRouteHandler extends ManagerBase implements RouteHandler {
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
} catch (InvalidParameterValueException e) {
io.notFound(resp, e.getMessage(), outFormat);
} catch (PermissionDeniedException e) {
io.badRequest(resp, e.getMessage(), outFormat);
}
}
}

View File

@ -29,6 +29,7 @@ import org.apache.cloudstack.veeam.VeeamControlServlet;
import org.apache.cloudstack.veeam.adapter.ServerAdapter;
import org.apache.cloudstack.veeam.api.dto.ImageTransfer;
import org.apache.cloudstack.veeam.api.dto.NamedList;
import org.apache.cloudstack.veeam.api.request.ListQuery;
import org.apache.cloudstack.veeam.utils.Negotiation;
import org.apache.cloudstack.veeam.utils.PathUtil;
import org.apache.commons.collections.CollectionUtils;
@ -105,7 +106,8 @@ public class ImageTransfersRouteHandler extends ManagerBase implements RouteHand
protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
final List<ImageTransfer> result = serverAdapter.listAllImageTransfers();
ListQuery query = ListQuery.fromRequest(req);
final List<ImageTransfer> result = serverAdapter.listAllImageTransfers(query.getOffset(), query.getLimit());
NamedList<ImageTransfer> response = NamedList.of("image_transfer", result);
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
}

View File

@ -84,7 +84,7 @@ public class JobsRouteHandler extends ManagerBase implements RouteHandler {
protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
final List<Job> result = serverAdapter.listAllJobs();
final List<Job> result = serverAdapter.listPendingJobs();
NamedList<Job> response = NamedList.of("job", result);
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
}

View File

@ -29,6 +29,7 @@ import org.apache.cloudstack.veeam.VeeamControlServlet;
import org.apache.cloudstack.veeam.adapter.ServerAdapter;
import org.apache.cloudstack.veeam.api.dto.NamedList;
import org.apache.cloudstack.veeam.api.dto.Network;
import org.apache.cloudstack.veeam.api.request.ListQuery;
import org.apache.cloudstack.veeam.utils.Negotiation;
import org.apache.cloudstack.veeam.utils.PathUtil;
import org.apache.commons.collections.CollectionUtils;
@ -84,7 +85,8 @@ public class NetworksRouteHandler extends ManagerBase implements RouteHandler {
protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
final List<Network> result = serverAdapter.listAllNetworks();
ListQuery query = ListQuery.fromRequest(req);
final List<Network> result = serverAdapter.listAllNetworks(query.getOffset(), query.getLimit());
NamedList<Network> response = NamedList.of("network", result);
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
}

View File

@ -29,6 +29,7 @@ import org.apache.cloudstack.veeam.VeeamControlServlet;
import org.apache.cloudstack.veeam.adapter.ServerAdapter;
import org.apache.cloudstack.veeam.api.dto.NamedList;
import org.apache.cloudstack.veeam.api.dto.Tag;
import org.apache.cloudstack.veeam.api.request.ListQuery;
import org.apache.cloudstack.veeam.utils.Negotiation;
import org.apache.cloudstack.veeam.utils.PathUtil;
import org.apache.commons.collections.CollectionUtils;
@ -85,7 +86,8 @@ public class TagsRouteHandler extends ManagerBase implements RouteHandler {
protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
final List<Tag> result = serverAdapter.listAllTags();
ListQuery query = ListQuery.fromRequest(req);
final List<Tag> result = serverAdapter.listAllTags(query.getOffset(), query.getLimit());
NamedList<Tag> response = NamedList.of("tag", result);
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
}

View File

@ -38,10 +38,7 @@ import org.apache.cloudstack.veeam.api.dto.ResourceAction;
import org.apache.cloudstack.veeam.api.dto.Snapshot;
import org.apache.cloudstack.veeam.api.dto.Vm;
import org.apache.cloudstack.veeam.api.dto.VmAction;
import org.apache.cloudstack.veeam.api.request.VmListQuery;
import org.apache.cloudstack.veeam.api.request.VmSearchExpr;
import org.apache.cloudstack.veeam.api.request.VmSearchFilters;
import org.apache.cloudstack.veeam.api.request.VmSearchParser;
import org.apache.cloudstack.veeam.api.request.ListQuery;
import org.apache.cloudstack.veeam.utils.Negotiation;
import org.apache.cloudstack.veeam.utils.PathUtil;
import org.apache.commons.collections.CollectionUtils;
@ -54,24 +51,10 @@ import com.fasterxml.jackson.core.JsonProcessingException;
public class VmsRouteHandler extends ManagerBase implements RouteHandler {
public static final String BASE_ROUTE = "/api/vms";
private static final int DEFAULT_MAX = 50;
private static final int HARD_CAP_MAX = 1000;
private static final int DEFAULT_PAGE = 1;
@Inject
ServerAdapter serverAdapter;
private VmSearchParser searchParser;
@Override
public boolean start() {
this.searchParser = new VmSearchParser(Set.of(
"id", "name", "status", "cluster", "host", "template"
));
return true;
}
@Override
public int priority() {
return 5;
@ -248,59 +231,12 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler {
protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
final VmListQuery q = fromRequest(req);
// Validate max/page early (optional strictness)
if (q.getMax() != null && q.getMax() <= 0) {
io.notFound(resp, "Invalid 'max' (must be > 0)", outFormat);
return;
}
if (q.getPage() != null && q.getPage() <= 0) {
io.notFound(resp, "Invalid 'page' (must be > 0)", outFormat);
return;
}
final int limit = q.resolvedMax(DEFAULT_MAX, HARD_CAP_MAX);
final int offset = q.offset(DEFAULT_MAX, HARD_CAP_MAX, DEFAULT_PAGE);
final VmSearchExpr expr;
try {
expr = searchParser.parse(q.getSearch());
} catch (VmSearchParser.VmSearchParseException e) {
io.notFound(resp, "Invalid search: " + e.getMessage(), outFormat);
return;
}
final VmSearchFilters filters;
try {
filters = VmSearchFilters.fromAndOnly(expr); // AND-only v1
} catch (VmSearchParser.VmSearchParseException e) {
io.notFound(resp, "Unsupported search: " + e.getMessage(), outFormat);
return;
}
final List<Vm> result = serverAdapter.listAllInstances();
ListQuery query = ListQuery.fromRequest(req);
final List<Vm> result = serverAdapter.listAllInstances(query.getOffset(), query.getLimit());
NamedList<Vm> response = NamedList.of("vm", result);
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
}
protected static VmListQuery fromRequest(final HttpServletRequest req) {
final VmListQuery q = new VmListQuery();
q.setSearch(req.getParameter("search"));
q.setMax(parseIntOrNull(req.getParameter("max")));
q.setPage(parseIntOrNull(req.getParameter("page")));
return q;
}
protected static Integer parseIntOrNull(final String s) {
if (s == null || s.trim().isEmpty()) return null;
try {
return Integer.parseInt(s.trim());
} catch (NumberFormatException e) {
return Integer.valueOf(-1); // will be rejected by validation above
}
}
protected void handlePost(final HttpServletRequest req, final HttpServletResponse resp,
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
String data = RouteHandler.getRequestData(req, logger);

View File

@ -29,6 +29,7 @@ import org.apache.cloudstack.veeam.VeeamControlServlet;
import org.apache.cloudstack.veeam.adapter.ServerAdapter;
import org.apache.cloudstack.veeam.api.dto.NamedList;
import org.apache.cloudstack.veeam.api.dto.VnicProfile;
import org.apache.cloudstack.veeam.api.request.ListQuery;
import org.apache.cloudstack.veeam.utils.Negotiation;
import org.apache.cloudstack.veeam.utils.PathUtil;
import org.apache.commons.collections.CollectionUtils;
@ -84,7 +85,8 @@ public class VnicProfilesRouteHandler extends ManagerBase implements RouteHandle
protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
final List<VnicProfile> result = serverAdapter.listAllVnicProfiles();
ListQuery query = ListQuery.fromRequest(req);
final List<VnicProfile> result = serverAdapter.listAllVnicProfiles(query.getOffset(), query.getLimit());
NamedList<VnicProfile> response = NamedList.of("vnic_profile", result);
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
}

View File

@ -73,7 +73,7 @@ public class HostJoinVOToHostConverter {
// --- Memory ---
h.setMemory(String.valueOf(vo.getTotalMemory()));
h.setMaxSchedulingMemory(String.valueOf(vo.getTotalMemory() - vo.getMemUsedCapacity())); // ToDo: check
h.setMaxSchedulingMemory(String.valueOf(vo.getTotalMemory() - vo.getMemUsedCapacity()));
// --- OS / versions (optional placeholders) ---
// If you want, you can set conservative defaults to match oVirt shape.

View File

@ -129,8 +129,9 @@ public final class UserVmJoinVOToVmConverter {
os.setBoot(boot);
dst.setOs(os);
Vm.Bios bios = Vm.Bios.getDefault();
Map<String, String> details = null;
if (detailsResolver != null) {
Map<String, String> details = detailsResolver.apply(src.getId());
details = detailsResolver.apply(src.getId());
Vm.Bios.updateBios(bios, MapUtils.getString(details, ApiConstants.BootType.UEFI.toString()));
}
dst.setBios(bios);
@ -167,6 +168,11 @@ public final class UserVmJoinVOToVmConverter {
dst.setInitialization(getOvfInitialization(dst, src));
}
dst.setAccountId(src.getAccountUuid());
dst.setAffinityGroupId(src.getAffinityGroupUuid());
dst.setUserDataId(src.getUserDataUuid());
dst.setDetails(details);
return dst;
}

View File

@ -21,8 +21,10 @@ import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import java.util.UUID;
@ -36,6 +38,7 @@ import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Document;
@ -195,6 +198,22 @@ public class OvfXmlUtil {
sb.append("</Entry>");
}
sb.append("</DataDiskOfferingIdMap>");
if (MapUtils.isNotEmpty(vm.getDetails())) {
sb.append("<Details>");
for (Map.Entry<String, String> entry : vm.getDetails().entrySet()) {
sb.append("<Detail>");
sb.append("<Key>").append(escapeText(entry.getKey())).append("</Key>");
sb.append("<Value>").append(escapeText(entry.getValue())).append("</Value>");
sb.append("</Detail>");
}
sb.append("</Details>");
}
if (vo.getUserDataId() != null) {
sb.append("<UserDataId>").append(escapeText(vo.getUserDataUuid())).append("</UserDataId>");
}
if (vo.getAffinityGroupId() != null) {
sb.append("<AffinityGroupId>").append(escapeText(vo.getAffinityGroupUuid())).append("</AffinityGroupId>");
}
sb.append("</CloudStack>");
sb.append("</Section>");
}
@ -518,14 +537,35 @@ public class OvfXmlUtil {
if (StringUtils.isNotBlank(serviceOfferingId)) {
vm.setCpuProfile(Ref.of("", serviceOfferingId));
}
}
private static String xpathString(XPath xpath, Document doc, String expression) {
String affinityGroupId = xpathString(xpath, metadataSection, ".//*[local-name()='AffinityGroupId']/text()");
if (StringUtils.isNotBlank(affinityGroupId)) {
vm.setAffinityGroupId(affinityGroupId);
}
String userDataId = xpathString(xpath, metadataSection, ".//*[local-name()='UserDataId']/text()");
if (StringUtils.isNotBlank(userDataId)) {
vm.setUserDataId(userDataId);
}
final Map<String, String> details = new HashMap<>();
try {
String value = (String) xpath.evaluate(expression, doc, XPathConstants.STRING);
return StringUtils.isBlank(value) ? null : value.trim();
} catch (XPathExpressionException e) {
return null;
NodeList detailNodes = (NodeList) xpath.evaluate(
".//*[local-name()='Details']/*[local-name()='Detail']",
metadataSection,
XPathConstants.NODESET
);
for (int i = 0; i < detailNodes.getLength(); i++) {
Node detailNode = detailNodes.item(i);
String key = xpathString(xpath, detailNode, "./*[local-name()='Key']/text()");
if (StringUtils.isBlank(key)) {
continue;
}
String value = xpathString(xpath, detailNode, "./*[local-name()='Value']/text()");
details.put(key, defaultString(value));
}
} catch (XPathExpressionException ignored) {
}
if (!details.isEmpty()) {
vm.setDetails(details);
}
}

View File

@ -18,6 +18,7 @@
package org.apache.cloudstack.veeam.api.dto;
import java.util.List;
import java.util.Map;
import org.apache.cloudstack.api.ApiConstants;
@ -79,6 +80,9 @@ public final class Vm extends BaseDto {
// CloudStack-specific fields
private String accountId;
private String affinityGroupId;
private String userDataId;
private Map<String, String> details;
public String getName() {
return name;
@ -297,6 +301,33 @@ public final class Vm extends BaseDto {
this.accountId = accountId;
}
@JsonIgnore
public String getAffinityGroupId() {
return affinityGroupId;
}
public void setAffinityGroupId(String affinityGroupId) {
this.affinityGroupId = affinityGroupId;
}
@JsonIgnore
public String getUserDataId() {
return userDataId;
}
public void setUserDataId(String userDataId) {
this.userDataId = userDataId;
}
@JsonIgnore
public Map<String, String> getDetails() {
return details;
}
public void setDetails(Map<String, String> details) {
this.details = details;
}
@JsonInclude(JsonInclude.Include.NON_NULL)
public static final class Bios {

View File

@ -0,0 +1,141 @@
// 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.veeam.api.request;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
public class ListQuery {
boolean allContent;
Long max;
Long page;
Map<String, String> search;
public boolean isAllContent() {
return allContent;
}
public void setAllContent(boolean allContent) {
this.allContent = allContent;
}
public Long getMax() {
return max;
}
public void setMax(Long max) {
this.max = max;
}
public Map<String, String> getSearch() {
return search;
}
public void setSearch(Map<String, String> search) {
this.search = search;
}
public Long getPage() {
return page;
}
public Long getOffset() {
if (page == null || max == null) {
return null;
}
return Math.max(0, (page - 1)) * max;
}
public Long getLimit() {
return max;
}
public static ListQuery fromRequest(HttpServletRequest request) {
ListQuery query = new ListQuery();
if (MapUtils.isEmpty(request.getParameterMap())) {
return query;
}
String allContent = request.getParameter("all_content");
if (StringUtils.isNotBlank(allContent)) {
query.setAllContent(Boolean.parseBoolean(allContent));
}
String max = request.getParameter("max");
if (StringUtils.isNotBlank(max)) {
try {
query.setMax(Long.parseLong(max));
} catch (NumberFormatException e) {
// Ignore invalid max and keep default null value.
}
}
Map<String, String> searchItems = getSearchMap(request.getParameter("search"));
if (!searchItems.isEmpty()) {
try {
query.setMax(Long.parseLong(searchItems.get("page")));
} catch (NumberFormatException e) {
// Ignore invalid page and keep default null value.
}
query.setSearch(searchItems);
}
return query;
}
// Parse search clause. Only keep items which use simple '=' operator, and ignore others. For example:
// name=myvm and status=up --> {name=myvm, status=up}
// name=myvm and status!=down --> {name=myvm} (ignore status!=down because it uses '!=' operator)
@NotNull
private static Map<String, String> getSearchMap(String searchClause) {
Map<String, String> searchItems = new LinkedHashMap<>();
if (StringUtils.isBlank(searchClause)) {
return searchItems;
}
String[] terms = searchClause.trim().split("(?i)\\s+and\\s+");
for (String term : terms) {
if (term == null) {
continue;
}
String trimmedTerm = term.trim();
if (trimmedTerm.isEmpty()) {
continue;
}
int eqIdx = trimmedTerm.indexOf('=');
if (eqIdx <= 0 || eqIdx != trimmedTerm.lastIndexOf('=')) {
continue;
}
char prev = trimmedTerm.charAt(eqIdx - 1);
if (prev == '!' || prev == '<' || prev == '>') {
continue;
}
String key = trimmedTerm.substring(0, eqIdx).trim();
String value = trimmedTerm.substring(eqIdx + 1).trim();
if (!key.isEmpty() && !value.isEmpty()) {
searchItems.put(key, value);
}
}
return searchItems;
}
}

View File

@ -26,6 +26,7 @@ import org.apache.cloudstack.api.response.HostResponse;
import com.cloud.api.query.vo.HostJoinVO;
import com.cloud.host.Host;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDao;
public interface HostJoinDao extends GenericDao<HostJoinVO, Long> {
@ -42,6 +43,6 @@ public interface HostJoinDao extends GenericDao<HostJoinVO, Long> {
List<HostJoinVO> findByClusterId(Long clusterId, Host.Type type);
List<HostJoinVO> listRoutingHostsByHypervisor(Hypervisor.HypervisorType hypervisorType);
List<HostJoinVO> listRoutingHostsByHypervisor(Hypervisor.HypervisorType hypervisorType, Filter filter);
}

View File

@ -55,6 +55,7 @@ import com.cloud.host.dao.HostDetailsDao;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.storage.StorageStats;
import com.cloud.user.AccountManager;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
@ -414,7 +415,7 @@ public class HostJoinDaoImpl extends GenericDaoBase<HostJoinVO, Long> implements
}
@Override
public List<HostJoinVO> listRoutingHostsByHypervisor(Hypervisor.HypervisorType hypervisorType) {
public List<HostJoinVO> listRoutingHostsByHypervisor(Hypervisor.HypervisorType hypervisorType, Filter filter) {
SearchBuilder<HostJoinVO> sb = createSearchBuilder();
sb.and("type", sb.entity().getType(), SearchCriteria.Op.EQ);
sb.and("hypervisorType", sb.entity().getHypervisorType(), SearchCriteria.Op.EQ);
@ -423,6 +424,6 @@ public class HostJoinDaoImpl extends GenericDaoBase<HostJoinVO, Long> implements
SearchCriteria<HostJoinVO> sc = sb.create();
sc.setParameters("type", Host.Type.Routing);
sc.setParameters("hypervisorType", hypervisorType);
return listBy(sc);
return listBy(sc, filter);
}
}

View File

@ -23,6 +23,7 @@ import org.apache.cloudstack.api.response.StoragePoolResponse;
import com.cloud.api.query.vo.StoragePoolJoinVO;
import com.cloud.storage.StoragePool;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
@ -44,4 +45,6 @@ public interface StoragePoolJoinDao extends GenericDao<StoragePoolJoinVO, Long>
List<StoragePoolVO> findStoragePoolByScopeAndRuleTags(Long datacenterId, Long podId, Long clusterId, ScopeType scopeType, List<String> tags);
List<StoragePoolJoinVO> listByZoneAndProvider(long zoneId, Filter filter);
}

View File

@ -49,6 +49,7 @@ import com.cloud.storage.StorageStats;
import com.cloud.storage.VolumeApiServiceImpl;
import com.cloud.user.AccountManager;
import com.cloud.utils.StringUtils;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
@ -410,4 +411,13 @@ public class StoragePoolJoinDaoImpl extends GenericDaoBase<StoragePoolJoinVO, Lo
return filteredPools;
}
@Override
public List<StoragePoolJoinVO> listByZoneAndProvider(long zoneId, Filter filter) {
SearchBuilder<StoragePoolJoinVO> sb = createSearchBuilder();
sb.and("zoneId", sb.entity().getZoneId(), SearchCriteria.Op.EQ);
sb.done();
SearchCriteria<StoragePoolJoinVO> sc = sb.create();
sc.setParameters("zoneId", zoneId);
return listBy(sc, filter);
}
}

View File

@ -20,6 +20,7 @@ import com.cloud.api.query.vo.UserVmJoinVO;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.user.Account;
import com.cloud.uservm.UserVm;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDao;
import com.cloud.vm.VirtualMachine;
import org.apache.cloudstack.api.ApiConstants.VMDetails;
@ -51,5 +52,5 @@ public interface UserVmJoinDao extends GenericDao<UserVmJoinVO, Long> {
List<UserVmJoinVO> listLeaseInstancesExpiringInDays(int days);
List<UserVmJoinVO> listByHypervisorType(Hypervisor.HypervisorType hypervisorType);
List<UserVmJoinVO> listByHypervisorType(Hypervisor.HypervisorType hypervisorType, Filter filter);
}

View File

@ -84,6 +84,7 @@ import com.cloud.user.UserStatisticsVO;
import com.cloud.user.dao.UserDao;
import com.cloud.user.dao.UserStatisticsDao;
import com.cloud.uservm.UserVm;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria.Op;
@ -498,7 +499,7 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
}
if (userVm.getUserDataId() != null) {
userVmResponse.setUserDataId(userVm.getUserDataUUid());
userVmResponse.setUserDataId(userVm.getUserDataUuid());
userVmResponse.setUserDataName(userVm.getUserDataName());
userVmResponse.setUserDataDetails(userVm.getUserDataDetails());
userVmResponse.setUserDataPolicy(userVm.getUserDataPolicy());
@ -835,12 +836,12 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
}
@Override
public List<UserVmJoinVO> listByHypervisorType(Hypervisor.HypervisorType hypervisorType) {
public List<UserVmJoinVO> listByHypervisorType(Hypervisor.HypervisorType hypervisorType, Filter filter) {
SearchBuilder<UserVmJoinVO> sb = createSearchBuilder();
sb.and("hypervisorType", sb.entity().getHypervisorType(), Op.EQ);
sb.done();
SearchCriteria<UserVmJoinVO> sc = sb.create();
sc.setParameters("hypervisorType", hypervisorType);
return listBy(sc);
return listBy(sc, filter);
}
}

View File

@ -24,6 +24,7 @@ import org.apache.cloudstack.api.response.VolumeResponse;
import com.cloud.api.query.vo.VolumeJoinVO;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.storage.Volume;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDao;
public interface VolumeJoinDao extends GenericDao<VolumeJoinVO, Long> {
@ -38,5 +39,5 @@ public interface VolumeJoinDao extends GenericDao<VolumeJoinVO, Long> {
List<VolumeJoinVO> listByInstanceId(long instanceId);
List<VolumeJoinVO> listByHypervisor(Hypervisor.HypervisorType hypervisorType);
List<VolumeJoinVO> listByHypervisor(Hypervisor.HypervisorType hypervisorType, Filter filter);
}

View File

@ -43,6 +43,7 @@ import com.cloud.storage.Volume;
import com.cloud.user.AccountManager;
import com.cloud.user.VmDiskStatisticsVO;
import com.cloud.user.dao.VmDiskStatisticsDao;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.vm.VirtualMachine;
@ -381,7 +382,7 @@ public class VolumeJoinDaoImpl extends GenericDaoBaseWithTagInformation<VolumeJo
}
@Override
public List<VolumeJoinVO> listByHypervisor(Hypervisor.HypervisorType hypervisorType) {
public List<VolumeJoinVO> listByHypervisor(Hypervisor.HypervisorType hypervisorType, Filter filter) {
SearchBuilder<VolumeJoinVO> sb = createSearchBuilder();
sb.and("vmType", sb.entity().getVmType(), SearchCriteria.Op.EQ);
sb.and("hypervisorType", sb.entity().getHypervisorType(), SearchCriteria.Op.EQ);
@ -389,7 +390,7 @@ public class VolumeJoinDaoImpl extends GenericDaoBaseWithTagInformation<VolumeJo
SearchCriteria<VolumeJoinVO> sc = sb.create();
sc.setParameters("vmType", VirtualMachine.Type.User);
sc.setParameters("hypervisorType", hypervisorType);
return search(sc, null);
return search(sc, filter);
}
}

View File

@ -429,7 +429,7 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
private int jobStatus;
@Column(name = "affinity_group_id")
private long affinityGroupId;
private Long affinityGroupId;
@Column(name = "affinity_group_uuid")
private String affinityGroupUuid;
@ -1012,7 +1012,7 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
return ip6Cidr;
}
public long getAffinityGroupId() {
public Long getAffinityGroupId() {
return affinityGroupId;
}
@ -1057,7 +1057,7 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
return userDataId;
}
public String getUserDataUUid() {
public String getUserDataUuid() {
return userDataUuid;
}

View File

@ -42,6 +42,7 @@ import org.apache.cloudstack.api.response.CheckpointResponse;
import org.apache.cloudstack.api.response.ImageTransferResponse;
import org.apache.cloudstack.backup.dao.BackupDao;
import org.apache.cloudstack.backup.dao.ImageTransferDao;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.managed.context.ManagedContextTimerTask;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
@ -67,6 +68,8 @@ import com.cloud.storage.VolumeStats;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.dao.VolumeDetailsDao;
import com.cloud.user.AccountService;
import com.cloud.user.User;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.exception.CloudRuntimeException;
@ -104,6 +107,9 @@ public class KVMBackupExportServiceImpl extends ManagerBase implements KVMBackup
@Inject
private PrimaryDataStoreDao primaryDataStoreDao;
@Inject
AccountService accountService;
private Timer imageTransferTimer;
private boolean isKVMBackupExportServiceSupported(Long zoneId) {
@ -493,8 +499,10 @@ public class KVMBackupExportServiceImpl extends ManagerBase implements KVMBackup
@Override
public ImageTransfer createImageTransfer(long volumeId, Long backupId, ImageTransfer.Direction direction, ImageTransfer.Format format) {
User callingUser = CallContext.current().getCallingUser();
ImageTransfer imageTransfer;
VolumeVO volume = volumeDao.findById(volumeId);
accountService.checkAccess(callingUser, volume);
if (volume == null) {
throw new CloudRuntimeException("Volume not found with the specified Id");

View File

@ -28,6 +28,7 @@ import com.cloud.network.dao.NetworkAccountVO;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.NetworkVO;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
@ -160,13 +161,18 @@ public class MockNetworkDaoImpl extends GenericDaoBase<NetworkVO, Long> implemen
return false;
}
@Override
public List<NetworkVO> listByZoneAndTrafficType(final long zoneId, final TrafficType trafficType, Filter filter) {
return null;
}
@Override
public List<NetworkVO> listByZoneAndTrafficType(final long zoneId, final TrafficType trafficType) {
return null;
}
@Override
public List<NetworkVO> listByTrafficType(final TrafficType trafficType) {
public List<NetworkVO> listByTrafficType(final TrafficType trafficType, Filter filter) {
return null;
}