mirror of https://github.com/apache/cloudstack.git
worker vm deployment wip
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
parent
ca4112e7d0
commit
a3669298af
|
|
@ -48,4 +48,12 @@ public class DeployVMCmdByAdmin extends DeployVMCmd implements AdminCmd {
|
|||
public Long getClusterId() {
|
||||
return clusterId;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
////////////////// Setters //////////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
public void setClusterId(Long clusterId) {
|
||||
this.clusterId = clusterId;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -193,6 +193,18 @@ public class ListServiceOfferingsCmd extends BaseListProjectAndAccountResourcesC
|
|||
return gpuEnabled;
|
||||
}
|
||||
|
||||
public void setZoneId(Long zoneId) {
|
||||
this.zoneId = zoneId;
|
||||
}
|
||||
|
||||
public void setCpuNumber(Integer cpuNumber) {
|
||||
this.cpuNumber = cpuNumber;
|
||||
}
|
||||
|
||||
public void setMemory(Integer memory) {
|
||||
this.memory = memory;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -100,6 +100,26 @@ public class AddNicToVMCmd extends BaseAsyncCmd implements UserCmd {
|
|||
return NetUtils.standardizeMacAddress(macaddr);
|
||||
}
|
||||
|
||||
public void setVmId(Long vmId) {
|
||||
this.vmId = vmId;
|
||||
}
|
||||
|
||||
public void setNetworkId(Long netId) {
|
||||
this.netId = netId;
|
||||
}
|
||||
|
||||
public void setIpaddr(String ipaddr) {
|
||||
this.ipaddr = ipaddr;
|
||||
}
|
||||
|
||||
public void setMacAddress(String macaddr) {
|
||||
this.macaddr = macaddr;
|
||||
}
|
||||
|
||||
public void setDhcpOptions(Map dhcpOptions) {
|
||||
this.dhcpOptions = dhcpOptions;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -798,6 +798,218 @@ public abstract class BaseDeployVMCmd extends BaseAsyncCreateCustomIdCmd impleme
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
////////////////// Setters //////////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
public void setZoneId(Long zoneId) {
|
||||
this.zoneId = zoneId;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public void setAccountName(String accountName) {
|
||||
this.accountName = accountName;
|
||||
}
|
||||
|
||||
public void setDomainId(Long domainId) {
|
||||
this.domainId = domainId;
|
||||
}
|
||||
|
||||
public void setNetworkIds(List<Long> networkIds) {
|
||||
this.networkIds = networkIds;
|
||||
}
|
||||
|
||||
public void setBootType(String bootType) {
|
||||
this.bootType = bootType;
|
||||
}
|
||||
|
||||
public void setBootMode(String bootMode) {
|
||||
this.bootMode = bootMode;
|
||||
}
|
||||
|
||||
public void setBootIntoSetup(Boolean bootIntoSetup) {
|
||||
this.bootIntoSetup = bootIntoSetup;
|
||||
}
|
||||
|
||||
public void setDiskOfferingId(Long diskOfferingId) {
|
||||
this.diskOfferingId = diskOfferingId;
|
||||
}
|
||||
|
||||
public void setSize(Long size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public void setRootdisksize(Long rootdisksize) {
|
||||
this.rootdisksize = rootdisksize;
|
||||
}
|
||||
|
||||
public void setDataDisksDetails(Map dataDisksDetails) {
|
||||
this.dataDisksDetails = dataDisksDetails;
|
||||
}
|
||||
|
||||
public void setGroup(String group) {
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
public void setHypervisor(String hypervisor) {
|
||||
this.hypervisor = hypervisor;
|
||||
}
|
||||
|
||||
public void setUserData(String userData) {
|
||||
this.userData = userData;
|
||||
}
|
||||
|
||||
public void setUserdataId(Long userdataId) {
|
||||
this.userdataId = userdataId;
|
||||
}
|
||||
|
||||
public void setUserdataDetails(Map userdataDetails) {
|
||||
this.userdataDetails = userdataDetails;
|
||||
}
|
||||
|
||||
public void setSshKeyPairName(String sshKeyPairName) {
|
||||
this.sshKeyPairName = sshKeyPairName;
|
||||
}
|
||||
|
||||
public void setSshKeyPairNames(List<String> sshKeyPairNames) {
|
||||
this.sshKeyPairNames = sshKeyPairNames;
|
||||
}
|
||||
|
||||
public void setHostId(Long hostId) {
|
||||
this.hostId = hostId;
|
||||
}
|
||||
|
||||
public void setSecurityGroupIdList(List<Long> securityGroupIdList) {
|
||||
this.securityGroupIdList = securityGroupIdList;
|
||||
}
|
||||
|
||||
public void setSecurityGroupNameList(List<String> securityGroupNameList) {
|
||||
this.securityGroupNameList = securityGroupNameList;
|
||||
}
|
||||
|
||||
public void setIpToNetworkList(Map ipToNetworkList) {
|
||||
this.ipToNetworkList = ipToNetworkList;
|
||||
}
|
||||
|
||||
public void setIpAddress(String ipAddress) {
|
||||
this.ipAddress = ipAddress;
|
||||
}
|
||||
|
||||
public void setIp6Address(String ip6Address) {
|
||||
this.ip6Address = ip6Address;
|
||||
}
|
||||
|
||||
public void setMacAddress(String macAddress) {
|
||||
this.macAddress = macAddress;
|
||||
}
|
||||
|
||||
public void setKeyboard(String keyboard) {
|
||||
this.keyboard = keyboard;
|
||||
}
|
||||
|
||||
public void setProjectId(Long projectId) {
|
||||
this.projectId = projectId;
|
||||
}
|
||||
|
||||
public void setStartVm(Boolean startVm) {
|
||||
this.startVm = startVm;
|
||||
}
|
||||
|
||||
public void setAffinityGroupIdList(List<Long> affinityGroupIdList) {
|
||||
this.affinityGroupIdList = affinityGroupIdList;
|
||||
}
|
||||
|
||||
public void setAffinityGroupNameList(List<String> affinityGroupNameList) {
|
||||
this.affinityGroupNameList = affinityGroupNameList;
|
||||
}
|
||||
|
||||
public void setDisplayVm(Boolean displayVm) {
|
||||
this.displayVm = displayVm;
|
||||
}
|
||||
|
||||
public void setDetails(Map details) {
|
||||
this.details = details;
|
||||
}
|
||||
|
||||
public void setDeploymentPlanner(String deploymentPlanner) {
|
||||
this.deploymentPlanner = deploymentPlanner;
|
||||
}
|
||||
|
||||
public void setDhcpOptionsNetworkList(Map dhcpOptionsNetworkList) {
|
||||
this.dhcpOptionsNetworkList = dhcpOptionsNetworkList;
|
||||
}
|
||||
|
||||
public void setDataDiskTemplateToDiskOfferingList(Map dataDiskTemplateToDiskOfferingList) {
|
||||
this.dataDiskTemplateToDiskOfferingList = dataDiskTemplateToDiskOfferingList;
|
||||
}
|
||||
|
||||
public void setExtraConfig(String extraConfig) {
|
||||
this.extraConfig = extraConfig;
|
||||
}
|
||||
|
||||
public void setCopyImageTags(Boolean copyImageTags) {
|
||||
this.copyImageTags = copyImageTags;
|
||||
}
|
||||
|
||||
public void setvAppProperties(Map vAppProperties) {
|
||||
this.vAppProperties = vAppProperties;
|
||||
}
|
||||
|
||||
public void setvAppNetworks(Map vAppNetworks) {
|
||||
this.vAppNetworks = vAppNetworks;
|
||||
}
|
||||
|
||||
public void setDynamicScalingEnabled(Boolean dynamicScalingEnabled) {
|
||||
this.dynamicScalingEnabled = dynamicScalingEnabled;
|
||||
}
|
||||
|
||||
public void setOverrideDiskOfferingId(Long overrideDiskOfferingId) {
|
||||
this.overrideDiskOfferingId = overrideDiskOfferingId;
|
||||
}
|
||||
|
||||
public void setIothreadsEnabled(Boolean iothreadsEnabled) {
|
||||
this.iothreadsEnabled = iothreadsEnabled;
|
||||
}
|
||||
|
||||
public void setIoDriverPolicy(String ioDriverPolicy) {
|
||||
this.ioDriverPolicy = ioDriverPolicy;
|
||||
}
|
||||
|
||||
public void setNicMultiqueueNumber(Integer nicMultiqueueNumber) {
|
||||
this.nicMultiqueueNumber = nicMultiqueueNumber;
|
||||
}
|
||||
|
||||
public void setNicPackedVirtQueues(Boolean nicPackedVirtQueues) {
|
||||
this.nicPackedVirtQueues = nicPackedVirtQueues;
|
||||
}
|
||||
|
||||
public void setLeaseDuration(Integer leaseDuration) {
|
||||
this.leaseDuration = leaseDuration;
|
||||
}
|
||||
|
||||
public void setLeaseExpiryAction(String leaseExpiryAction) {
|
||||
this.leaseExpiryAction = leaseExpiryAction;
|
||||
}
|
||||
|
||||
public void setExternalDetails(Map externalDetails) {
|
||||
this.externalDetails = externalDetails;
|
||||
}
|
||||
|
||||
public void setDataDiskInfoList(List<VmDiskInfo> dataDiskInfoList) {
|
||||
this.dataDiskInfoList = dataDiskInfoList;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ public class DeployVMCmd extends BaseDeployVMCmd {
|
|||
@Parameter(name = ApiConstants.SNAPSHOT_ID, type = CommandType.UUID, entityType = SnapshotResponse.class, since = "4.21")
|
||||
private Long snapshotId;
|
||||
|
||||
@Parameter(name = ApiConstants.DUMMY, type = CommandType.BOOLEAN, since = "4.23", description = "Deploy a dummy VM without any disk. False by default. This supports KVM only.")
|
||||
private Boolean dummy;
|
||||
@Parameter(name = "blank", type = CommandType.BOOLEAN, since = "4.22.1")
|
||||
private Boolean blankInstance;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -88,14 +88,38 @@ public class DeployVMCmd extends BaseDeployVMCmd {
|
|||
return snapshotId;
|
||||
}
|
||||
|
||||
public boolean getDummy() {
|
||||
return dummy != null && dummy;
|
||||
}
|
||||
|
||||
public boolean isVolumeOrSnapshotProvided() {
|
||||
return volumeId != null || snapshotId != null;
|
||||
}
|
||||
|
||||
public boolean isBlankInstance() {
|
||||
return Boolean.TRUE.equals(blankInstance);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
////////////////// Setters //////////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
public void setServiceOfferingId(Long serviceOfferingId) {
|
||||
this.serviceOfferingId = serviceOfferingId;
|
||||
}
|
||||
|
||||
public void setTemplateId(Long templateId) {
|
||||
this.templateId = templateId;
|
||||
}
|
||||
|
||||
public void setVolumeId(Long volumeId) {
|
||||
this.volumeId = volumeId;
|
||||
}
|
||||
|
||||
public void setSnapshotId(Long snapshotId) {
|
||||
this.snapshotId = snapshotId;
|
||||
}
|
||||
|
||||
public void setBlankInstance(boolean blankInstance) {
|
||||
this.blankInstance = blankInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
UserVm result;
|
||||
|
|
@ -140,7 +164,7 @@ public class DeployVMCmd extends BaseDeployVMCmd {
|
|||
|
||||
@Override
|
||||
public void create() throws ResourceAllocationException {
|
||||
if (!getDummy() && Stream.of(templateId, snapshotId, volumeId).filter(Objects::nonNull).count() != 1) {
|
||||
if (!isBlankInstance() && Stream.of(templateId, snapshotId, volumeId).filter(Objects::nonNull).count() != 1) {
|
||||
throw new CloudRuntimeException("Please provide only one of the following parameters - template ID, volume ID or snapshot ID");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -64,12 +64,16 @@ public interface IncrementalBackupService extends Configurable, PluggableService
|
|||
|
||||
ImageTransfer createImageTransfer(long volumeId, Long backupId, ImageTransfer.Direction direction);
|
||||
|
||||
boolean cancelImageTransfer(long imageTransferId);
|
||||
|
||||
/**
|
||||
* Finalize an image transfer
|
||||
* Marks transfer as complete (NBD is closed globally in finalize backup)
|
||||
*/
|
||||
boolean finalizeImageTransfer(FinalizeImageTransferCmd cmd);
|
||||
|
||||
boolean finalizeImageTransfer(long imageTransferId);
|
||||
|
||||
/**
|
||||
* List image transfers for a backup
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -577,7 +577,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||
|
||||
logger.debug("Allocating disks for {}", persistedVm);
|
||||
|
||||
if (_userVmMgr.isDummyTemplate(hyperType, template.getId())) {
|
||||
if (_userVmMgr.isBlankInstanceTemplate(template)) {
|
||||
logger.debug("Template is a dummy template for hypervisor {}, skipping volume allocation", hyperType);
|
||||
return;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,833 @@
|
|||
// 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.adapter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.cloudstack.acl.Role;
|
||||
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.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.command.admin.vm.DeployVMCmdByAdmin;
|
||||
import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd;
|
||||
import org.apache.cloudstack.api.command.user.network.ListNetworksCmd;
|
||||
import org.apache.cloudstack.api.command.user.offering.ListServiceOfferingsCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.DeployVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.ListVMsCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.StartVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.StopVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.DeleteVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.ListVolumesCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
|
||||
import org.apache.cloudstack.api.response.ListResponse;
|
||||
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
|
||||
import org.apache.cloudstack.backup.ImageTransfer.Direction;
|
||||
import org.apache.cloudstack.backup.ImageTransferVO;
|
||||
import org.apache.cloudstack.backup.IncrementalBackupService;
|
||||
import org.apache.cloudstack.backup.dao.ImageTransferDao;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.query.QueryService;
|
||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||
import org.apache.cloudstack.veeam.api.converter.AsyncJobJoinVOToJobConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.ClusterVOToClusterConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.DataCenterJoinVOToDataCenterConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.HostJoinVOToHostConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.ImageTransferVOToImageTransferConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.NetworkVOToNetworkConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.NetworkVOToVnicProfileConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.NicVOToNicConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.StoreVOToStorageDomainConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.UserVmJoinVOToVmConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.VolumeJoinVOToDiskConverter;
|
||||
import org.apache.cloudstack.veeam.api.dto.Cluster;
|
||||
import org.apache.cloudstack.veeam.api.dto.DataCenter;
|
||||
import org.apache.cloudstack.veeam.api.dto.Disk;
|
||||
import org.apache.cloudstack.veeam.api.dto.DiskAttachment;
|
||||
import org.apache.cloudstack.veeam.api.dto.Host;
|
||||
import org.apache.cloudstack.veeam.api.dto.ImageTransfer;
|
||||
import org.apache.cloudstack.veeam.api.dto.Job;
|
||||
import org.apache.cloudstack.veeam.api.dto.Network;
|
||||
import org.apache.cloudstack.veeam.api.dto.Nic;
|
||||
import org.apache.cloudstack.veeam.api.dto.Ref;
|
||||
import org.apache.cloudstack.veeam.api.dto.StorageDomain;
|
||||
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.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
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.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;
|
||||
import com.cloud.dc.ClusterVO;
|
||||
import com.cloud.dc.DataCenterVO;
|
||||
import com.cloud.dc.dao.ClusterDao;
|
||||
import com.cloud.dc.dao.DataCenterDao;
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.exception.OperationTimedoutException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.hypervisor.Hypervisor;
|
||||
import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.dao.NetworkVO;
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
import com.cloud.org.Grouping;
|
||||
import com.cloud.service.dao.ServiceOfferingDao;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.VolumeApiService;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.dao.VolumeDao;
|
||||
import com.cloud.storage.dao.VolumeDetailsDao;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountService;
|
||||
import com.cloud.user.AccountVO;
|
||||
import com.cloud.user.User;
|
||||
import com.cloud.user.UserAccount;
|
||||
import com.cloud.user.dao.AccountDao;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.utils.EnumUtils;
|
||||
import com.cloud.utils.component.ComponentContext;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.vm.NicVO;
|
||||
import com.cloud.vm.UserVmService;
|
||||
import com.cloud.vm.UserVmVO;
|
||||
import com.cloud.vm.dao.NicDao;
|
||||
import com.cloud.vm.dao.UserVmDao;
|
||||
|
||||
public class ServerAdapter extends ManagerBase {
|
||||
private static final String SERVICE_ACCOUNT_NAME = "veemserviceuser";
|
||||
private static final String SERVICE_ACCOUNT_ROLE_NAME = "Veeam Service Role";
|
||||
private static final String SERVICE_ACCOUNT_FIRST_NAME = "Veeam";
|
||||
private static final String SERVICE_ACCOUNT_LAST_NAME = "Service User";
|
||||
private static final List<Class<?>> SERVICE_ACCOUNT_ROLE_ALLOWED_APIS = Arrays.asList(
|
||||
QueryAsyncJobResultCmd.class,
|
||||
ListVMsCmd.class,
|
||||
DeployVMCmd.class,
|
||||
StartVMCmd.class,
|
||||
StopVMCmd.class,
|
||||
DestroyVMCmd.class,
|
||||
ListVolumesCmd.class,
|
||||
CreateVolumeCmd.class,
|
||||
DeleteVolumeCmd.class,
|
||||
AttachVolumeCmd.class,
|
||||
DetachVolumeCmd.class,
|
||||
ResizeVolumeCmd.class,
|
||||
ListNetworksCmd.class
|
||||
);
|
||||
|
||||
@Inject
|
||||
RoleService roleService;
|
||||
|
||||
@Inject
|
||||
AccountService accountService;
|
||||
|
||||
@Inject
|
||||
AccountDao accountDao;
|
||||
|
||||
@Inject
|
||||
DataCenterDao dataCenterDao;
|
||||
|
||||
@Inject
|
||||
DataCenterJoinDao dataCenterJoinDao;
|
||||
|
||||
@Inject
|
||||
StoragePoolJoinDao storagePoolJoinDao;
|
||||
|
||||
@Inject
|
||||
ImageStoreJoinDao imageStoreJoinDao;
|
||||
|
||||
@Inject
|
||||
ClusterDao clusterDao;
|
||||
|
||||
@Inject
|
||||
HostJoinDao hostJoinDao;
|
||||
|
||||
@Inject
|
||||
NetworkDao networkDao;
|
||||
|
||||
@Inject
|
||||
UserVmDao userVmDao;
|
||||
|
||||
@Inject
|
||||
UserVmJoinDao userVmJoinDao;
|
||||
|
||||
@Inject
|
||||
VolumeDao volumeDao;
|
||||
|
||||
@Inject
|
||||
VolumeJoinDao volumeJoinDao;
|
||||
|
||||
@Inject
|
||||
VolumeDetailsDao volumeDetailsDao;
|
||||
|
||||
@Inject
|
||||
VolumeApiService volumeApiService;
|
||||
|
||||
@Inject
|
||||
PrimaryDataStoreDao primaryDataStoreDao;
|
||||
|
||||
@Inject
|
||||
ImageTransferDao imageTransferDao;
|
||||
|
||||
@Inject
|
||||
IncrementalBackupService incrementalBackupService;
|
||||
|
||||
@Inject
|
||||
QueryService queryService;
|
||||
|
||||
@Inject
|
||||
ServiceOfferingDao serviceOfferingDao;
|
||||
|
||||
@Inject
|
||||
UserVmService userVmService;
|
||||
|
||||
@Inject
|
||||
NicDao nicDao;
|
||||
|
||||
private Map<String, Long> jobsMap = new ConcurrentHashMap<>();
|
||||
|
||||
protected Role createServiceAccountRole() {
|
||||
Role role = roleService.createRole(SERVICE_ACCOUNT_ROLE_NAME, RoleType.User,
|
||||
SERVICE_ACCOUNT_ROLE_NAME, false);
|
||||
for (Class<?> allowedApi : SERVICE_ACCOUNT_ROLE_ALLOWED_APIS) {
|
||||
final String apiName = BaseCmd.getCommandNameByClass(allowedApi);
|
||||
roleService.createRolePermission(role, new Rule(apiName), RolePermissionEntity.Permission.ALLOW,
|
||||
String.format("Allow %s", apiName));
|
||||
}
|
||||
roleService.createRolePermission(role, new Rule("*"), RolePermissionEntity.Permission.DENY,
|
||||
"Deny all");
|
||||
logger.debug("Created default role for Veeam service account in projects: {}", role);
|
||||
return role;
|
||||
}
|
||||
|
||||
public Role getServiceAccountRole() {
|
||||
List<Role> roles = roleService.findRolesByName(SERVICE_ACCOUNT_ROLE_NAME);
|
||||
if (CollectionUtils.isNotEmpty(roles)) {
|
||||
Role role = roles.get(0);
|
||||
logger.debug("Found default role for Veeam service account in projects: {}", role);
|
||||
return role;
|
||||
}
|
||||
return createServiceAccountRole();
|
||||
}
|
||||
|
||||
protected Account createServiceAccount() {
|
||||
CallContext.register(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM);
|
||||
try {
|
||||
Role role = getServiceAccountRole();
|
||||
UserAccount userAccount = accountService.createUserAccount(SERVICE_ACCOUNT_NAME,
|
||||
UUID.randomUUID().toString(), SERVICE_ACCOUNT_FIRST_NAME,
|
||||
SERVICE_ACCOUNT_LAST_NAME, null, null, SERVICE_ACCOUNT_NAME, Account.Type.NORMAL, role.getId(),
|
||||
1L, null, null, null, null, User.Source.NATIVE);
|
||||
Account account = accountService.getAccount(userAccount.getAccountId());
|
||||
logger.debug("Created Veeam service account: {}", account);
|
||||
return account;
|
||||
} finally {
|
||||
CallContext.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
protected Account createServiceAccountIfNeeded() {
|
||||
List<AccountVO> accounts = accountDao.findAccountsByName(SERVICE_ACCOUNT_NAME);
|
||||
for (AccountVO account : accounts) {
|
||||
if (Account.State.ENABLED.equals(account.getState())) {
|
||||
logger.debug("Veeam service account found: {}", account);
|
||||
return account;
|
||||
}
|
||||
}
|
||||
return createServiceAccount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean start() {
|
||||
createServiceAccountIfNeeded();
|
||||
//find public custom disk offering
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<DataCenter> listAllDataCenters() {
|
||||
final List<DataCenterJoinVO> clusters = dataCenterJoinDao.listAll();
|
||||
return DataCenterJoinVOToDataCenterConverter.toDCList(clusters);
|
||||
}
|
||||
|
||||
public DataCenter getDataCenter(String uuid) {
|
||||
final DataCenterJoinVO vo = dataCenterJoinDao.findByUuid(uuid);
|
||||
if (vo == null) {
|
||||
throw new InvalidParameterValueException("DataCenter with ID " + uuid + " not found");
|
||||
}
|
||||
return DataCenterJoinVOToDataCenterConverter.toDataCenter(vo);
|
||||
}
|
||||
|
||||
public List<StorageDomain> listStorageDomainsByDcId(final String uuid) {
|
||||
final DataCenterJoinVO dataCenterVO = dataCenterJoinDao.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;
|
||||
}
|
||||
|
||||
public List<Network> listNetworksByDcId(final String uuid) {
|
||||
final DataCenterJoinVO dataCenterVO = dataCenterJoinDao.findByUuid(uuid);
|
||||
if (dataCenterVO == null) {
|
||||
throw new InvalidParameterValueException("DataCenter with ID " + uuid + " not found");
|
||||
}
|
||||
List<NetworkVO> networks = networkDao.listAll();
|
||||
return NetworkVOToNetworkConverter.toNetworkList(networks, (dcId) -> dataCenterVO);
|
||||
}
|
||||
|
||||
public List<Cluster> listAllClusters() {
|
||||
final List<ClusterVO> clusters = clusterDao.listAll();
|
||||
return ClusterVOToClusterConverter.toClusterList(clusters, this::getZoneById);
|
||||
}
|
||||
|
||||
public Cluster getCluster(String uuid) {
|
||||
final ClusterVO vo = clusterDao.findByUuid(uuid);
|
||||
if (vo == null) {
|
||||
throw new InvalidParameterValueException("Cluster with ID " + uuid + " not found");
|
||||
}
|
||||
return ClusterVOToClusterConverter.toCluster(vo, this::getZoneById);
|
||||
}
|
||||
|
||||
public List<Host> listAllHosts() {
|
||||
final List<HostJoinVO> hosts = hostJoinDao.listAll();
|
||||
return HostJoinVOToHostConverter.toHostList(hosts);
|
||||
}
|
||||
|
||||
public Host getHost(String uuid) {
|
||||
final HostJoinVO vo = hostJoinDao.findByUuid(uuid);
|
||||
if (vo == null) {
|
||||
throw new InvalidParameterValueException("Host with ID " + uuid + " not found");
|
||||
}
|
||||
return HostJoinVOToHostConverter.toHost(vo);
|
||||
}
|
||||
|
||||
public List<Network> listAllNetworks() {
|
||||
final List<NetworkVO> networks = networkDao.listAll();
|
||||
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");
|
||||
}
|
||||
return NetworkVOToNetworkConverter.toNetwork(vo, this::getZoneById);
|
||||
}
|
||||
|
||||
public List<VnicProfile> listAllVnicProfiles() {
|
||||
final List<NetworkVO> networks = networkDao.listAll();
|
||||
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");
|
||||
}
|
||||
return NetworkVOToVnicProfileConverter.toVnicProfile(vo, this::getZoneById);
|
||||
}
|
||||
|
||||
public List<Vm> listAllUserVms() {
|
||||
// Todo: add filtering, pagination
|
||||
List<UserVmJoinVO> vms = userVmJoinDao.listAll();
|
||||
return UserVmJoinVOToVmConverter.toVmList(vms, this::getHostById);
|
||||
}
|
||||
|
||||
public Vm getVm(String uuid) {
|
||||
UserVmJoinVO vo = userVmJoinDao.findByUuid(uuid);
|
||||
if (vo == null) {
|
||||
throw new InvalidParameterValueException("VM with ID " + uuid + " not found");
|
||||
}
|
||||
return UserVmJoinVOToVmConverter.toVm(vo, this::getHostById, this::listDiskAttachmentsByInstanceId,
|
||||
this::listNicsByInstance);
|
||||
}
|
||||
|
||||
public Vm handleCreateVm(Vm request) {
|
||||
if (request == null) {
|
||||
throw new InvalidParameterValueException("Request disk data is empty");
|
||||
}
|
||||
String name = request.name;
|
||||
Long zoneId = null;
|
||||
Long clusterId = null;
|
||||
if (request.cluster != null && StringUtils.isNotEmpty(request.cluster.id)) {
|
||||
ClusterVO clusterVO = clusterDao.findByUuid(request.cluster.id);
|
||||
if (clusterVO != null) {
|
||||
zoneId = clusterVO.getDataCenterId();
|
||||
clusterId = clusterVO.getId();
|
||||
}
|
||||
}
|
||||
if (zoneId == null) {
|
||||
throw new InvalidParameterValueException("Failed to determine datacenter for VM creation request");
|
||||
}
|
||||
Integer cpu = null;
|
||||
try {
|
||||
cpu = request.cpu.topology.sockets;
|
||||
} catch (Exception ignored) {}
|
||||
if (cpu == null) {
|
||||
throw new InvalidParameterValueException("CPU topology sockets must be specified");
|
||||
}
|
||||
Long memory = null;
|
||||
try {
|
||||
memory = request.memory;
|
||||
} catch (Exception ignored) {}
|
||||
if (memory == null) {
|
||||
throw new InvalidParameterValueException("Memory must be specified");
|
||||
}
|
||||
String userdata = null;
|
||||
if (request.getInitialization() != null) {
|
||||
userdata = request.getInitialization().getContentData();
|
||||
}
|
||||
ApiConstants.BootType bootType = ApiConstants.BootType.BIOS;
|
||||
ApiConstants.BootMode bootMode = ApiConstants.BootMode.LEGACY;
|
||||
if (request.bios != null && StringUtils.isNotEmpty(request.bios.type) && request.bios.type.contains("secure")) {
|
||||
bootType = ApiConstants.BootType.UEFI;
|
||||
bootMode = ApiConstants.BootMode.SECURE;
|
||||
}
|
||||
Account serviceAccount = createServiceAccountIfNeeded();
|
||||
CallContext.register(serviceAccount.getId(), serviceAccount.getId());
|
||||
try {
|
||||
return createVm(zoneId, clusterId, name, cpu, memory, userdata, bootType, bootMode);
|
||||
} finally {
|
||||
CallContext.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
protected ServiceOffering getServiceOfferingIdForVmCreation(long zoneId, int cpu, long memory) {
|
||||
ListServiceOfferingsCmd cmd = new ListServiceOfferingsCmd();
|
||||
ComponentContext.inject(cmd);
|
||||
cmd.setZoneId(zoneId);
|
||||
cmd.setCpuNumber(cpu);
|
||||
Integer memoryMB = (int)(memory / (1024L * 1024L));
|
||||
cmd.setMemory(memoryMB);
|
||||
ListResponse<ServiceOfferingResponse> offerings = queryService.searchForServiceOfferings(cmd);
|
||||
if (offerings.getResponses().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
String uuid = offerings.getResponses().get(0).getId();
|
||||
return serviceOfferingDao.findByUuid(uuid);
|
||||
}
|
||||
|
||||
protected Vm createVm(Long zoneId, Long clusterId, String name, int cpu, long memory, String userdata,
|
||||
ApiConstants.BootType bootType, ApiConstants.BootMode bootMode) {
|
||||
ServiceOffering serviceOffering = getServiceOfferingIdForVmCreation(zoneId, cpu, memory);
|
||||
if (serviceOffering == null) {
|
||||
throw new CloudRuntimeException("No service offering found for VM creation with specified CPU and memory");
|
||||
}
|
||||
DeployVMCmdByAdmin cmd = new DeployVMCmdByAdmin();
|
||||
ComponentContext.inject(cmd);
|
||||
cmd.setZoneId(zoneId);
|
||||
cmd.setClusterId(clusterId);
|
||||
cmd.setName(name);
|
||||
cmd.setServiceOfferingId(serviceOffering.getId());
|
||||
if (StringUtils.isNotEmpty(userdata)) {
|
||||
cmd.setUserData(Base64.getEncoder().encodeToString(userdata.getBytes()));
|
||||
}
|
||||
if (bootType != null) {
|
||||
cmd.setBootType(bootType.toString());
|
||||
}
|
||||
if (bootMode != null) {
|
||||
cmd.setBootMode(bootMode.toString());
|
||||
}
|
||||
// ToDo: handle other.
|
||||
cmd.setHypervisor(Hypervisor.HypervisorType.KVM.name());
|
||||
cmd.setBlankInstance(true);
|
||||
try {
|
||||
UserVm vm = userVmService.createVirtualMachine(cmd);
|
||||
vm = userVmService.finalizeCreateVirtualMachine(vm.getId());
|
||||
UserVmJoinVO vo = userVmJoinDao.findById(vm.getId());
|
||||
return UserVmJoinVOToVmConverter.toVm(vo, this::getHostById, this::listDiskAttachmentsByInstanceId,
|
||||
this::listNicsByInstance);
|
||||
} catch (InsufficientCapacityException | ResourceUnavailableException | ResourceAllocationException | CloudRuntimeException e) {
|
||||
throw new CloudRuntimeException("Failed to create VM: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteVm(String uuid) {
|
||||
UserVmVO vo = userVmDao.findByUuid(uuid);
|
||||
if (vo == null) {
|
||||
throw new InvalidParameterValueException("VM with ID " + uuid + " not found");
|
||||
}
|
||||
try {
|
||||
userVmService.destroyVm(vo.getId(), true);
|
||||
} catch (ResourceUnavailableException e) {
|
||||
throw new CloudRuntimeException("Failed to delete VM: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public VmAction startVm(String uuid) {
|
||||
UserVmVO vo = userVmDao.findByUuid(uuid);
|
||||
if (vo == null) {
|
||||
throw new InvalidParameterValueException("VM with ID " + uuid + " not found");
|
||||
}
|
||||
try {
|
||||
userVmService.startVirtualMachine(vo, null);
|
||||
return UserVmJoinVOToVmConverter.toVmAction(userVmJoinDao.findById(vo.getId()));
|
||||
} catch (ResourceUnavailableException | OperationTimedoutException | InsufficientCapacityException | CloudRuntimeException e) {
|
||||
throw new CloudRuntimeException("Failed to start VM: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public VmAction stopVm(String uuid) {
|
||||
UserVmVO vo = userVmDao.findByUuid(uuid);
|
||||
if (vo == null) {
|
||||
throw new InvalidParameterValueException("VM with ID " + uuid + " not found");
|
||||
}
|
||||
try {
|
||||
userVmService.stopVirtualMachine(vo.getId(), true);
|
||||
return UserVmJoinVOToVmConverter.toVmAction(userVmJoinDao.findById(vo.getId()));
|
||||
} catch (CloudRuntimeException e) {
|
||||
throw new CloudRuntimeException("Failed to stop VM: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public VmAction shutdownVm(String uuid) {
|
||||
UserVmVO vo = userVmDao.findByUuid(uuid);
|
||||
if (vo == null) {
|
||||
throw new InvalidParameterValueException("VM with ID " + uuid + " not found");
|
||||
}
|
||||
try {
|
||||
userVmService.stopVirtualMachine(vo.getId(), false);
|
||||
return UserVmJoinVOToVmConverter.toVmAction(userVmJoinDao.findById(vo.getId()));
|
||||
} catch (CloudRuntimeException e) {
|
||||
throw new CloudRuntimeException("Failed to shutdown VM: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Disk> listAllDisks() {
|
||||
List<VolumeJoinVO> kvmVolumes = volumeJoinDao.listByHypervisor(Hypervisor.HypervisorType.KVM);
|
||||
return VolumeJoinVOToDiskConverter.toDiskList(kvmVolumes);
|
||||
}
|
||||
|
||||
public Disk getDisk(String uuid) {
|
||||
VolumeJoinVO vo = volumeJoinDao.findByUuid(uuid);
|
||||
if (vo == null) {
|
||||
throw new InvalidParameterValueException("Disk with ID " + uuid + " not found");
|
||||
}
|
||||
return VolumeJoinVOToDiskConverter.toDisk(vo);
|
||||
}
|
||||
|
||||
protected List<DiskAttachment> listDiskAttachmentsByInstanceId(final long instanceId) {
|
||||
List<VolumeJoinVO> kvmVolumes = volumeJoinDao.listByInstanceId(instanceId);
|
||||
return VolumeJoinVOToDiskConverter.toDiskAttachmentList(kvmVolumes);
|
||||
}
|
||||
|
||||
public List<DiskAttachment> listDiskAttachmentsByInstanceUuid(final String uuid) {
|
||||
UserVmVO vo = userVmDao.findByUuid(uuid);
|
||||
if (vo == null) {
|
||||
throw new InvalidParameterValueException("VM with ID " + uuid + " not found");
|
||||
}
|
||||
return listDiskAttachmentsByInstanceId(vo.getId());
|
||||
}
|
||||
|
||||
public DiskAttachment handleVmAttachDisk(final String vmUuid, final DiskAttachment request) {
|
||||
UserVmVO vmVo = userVmDao.findByUuid(vmUuid);
|
||||
if (vmVo == null) {
|
||||
throw new InvalidParameterValueException("VM with ID " + vmUuid + " not found");
|
||||
}
|
||||
if (request == null || request.disk == null || StringUtils.isEmpty(request.disk.id)) {
|
||||
throw new InvalidParameterValueException("Request disk data is empty");
|
||||
}
|
||||
VolumeVO volumeVO = volumeDao.findByUuid(request.disk.id);
|
||||
if (volumeVO == null) {
|
||||
throw new InvalidParameterValueException("Disk with ID " + request.disk.id + " not found");
|
||||
}
|
||||
Account serviceAccount = createServiceAccountIfNeeded();
|
||||
CallContext.register(serviceAccount.getId(), serviceAccount.getId());
|
||||
try {
|
||||
Volume volume = volumeApiService.attachVolumeToVM(vmVo.getId(), volumeVO.getId(), 0L, false);
|
||||
VolumeJoinVO attachedVolumeVO = volumeJoinDao.findById(volume.getId());
|
||||
return VolumeJoinVOToDiskConverter.toDiskAttachment(attachedVolumeVO);
|
||||
} finally {
|
||||
CallContext.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteDisk(String uuid) {
|
||||
VolumeVO vo = volumeDao.findByUuid(uuid);
|
||||
if (vo == null) {
|
||||
throw new InvalidParameterValueException("Disk with ID " + uuid + " not found");
|
||||
}
|
||||
volumeApiService.deleteVolume(vo.getId(), accountService.getSystemAccount());
|
||||
}
|
||||
|
||||
public Disk handleCreateDisk(Disk request) {
|
||||
if (request == null) {
|
||||
throw new InvalidParameterValueException("Request disk data is empty");
|
||||
}
|
||||
String name = request.name;
|
||||
if (StringUtils.isBlank(name) && !name.startsWith("Veeam_KvmBackupDisk_")) {
|
||||
throw new InvalidParameterValueException("Only worker VM disk creation is supported");
|
||||
}
|
||||
if (request.storageDomains == null || CollectionUtils.isEmpty(request.storageDomains.storageDomain) ||
|
||||
request.storageDomains.storageDomain.size() > 1) {
|
||||
throw new InvalidParameterValueException("Exactly one storage domain must be specified");
|
||||
}
|
||||
Ref domain = request.storageDomains.storageDomain.get(0);
|
||||
if (domain == null || domain.id == null) {
|
||||
throw new InvalidParameterValueException("Storage domain ID must be specified");
|
||||
}
|
||||
StoragePoolVO pool = primaryDataStoreDao.findByUuid(domain.id);
|
||||
if (pool == null) {
|
||||
throw new InvalidParameterValueException("Storage domain with ID " + domain.id + " not found");
|
||||
}
|
||||
String sizeStr = request.provisionedSize;
|
||||
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");
|
||||
}
|
||||
provisionedSizeInGb = Math.max(1L, provisionedSizeInGb / (1024L * 1024L * 1024L));
|
||||
Long initialSize = null;
|
||||
if (StringUtils.isNotBlank(request.initialSize)) {
|
||||
try {
|
||||
initialSize = Long.parseLong(request.initialSize);
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
Account serviceAccount = createServiceAccountIfNeeded();
|
||||
DataCenterVO zone = dataCenterDao.findById(pool.getDataCenterId());
|
||||
if (zone == null || !Grouping.AllocationState.Enabled.equals(zone.getAllocationState())) {
|
||||
throw new InvalidParameterValueException("Datacenter for the specified storage domain is not found or not active");
|
||||
}
|
||||
Long diskOfferingId = volumeApiService.getCustomDiskOfferingIdForVolumeUpload(serviceAccount, zone);
|
||||
if (diskOfferingId == null) {
|
||||
throw new CloudRuntimeException("Failed to find custom offering for disk" + zone.getName());
|
||||
}
|
||||
CallContext.register(serviceAccount.getId(), serviceAccount.getId());
|
||||
try {
|
||||
return createDisk(serviceAccount, pool, name, diskOfferingId, provisionedSizeInGb, initialSize);
|
||||
} finally {
|
||||
CallContext.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Disk createDisk(Account serviceAccount, StoragePoolVO pool, String name, Long diskOfferingId, long sizeInGb, Long initialSize) {
|
||||
Volume volume;
|
||||
try {
|
||||
volume = volumeApiService.allocVolume(serviceAccount.getId(), pool.getDataCenterId(), diskOfferingId, null,
|
||||
null, name, sizeInGb, null, null, null, null);
|
||||
} catch (ResourceAllocationException e) {
|
||||
throw new CloudRuntimeException(e.getMessage(), e);
|
||||
}
|
||||
if (volume == null) {
|
||||
throw new CloudRuntimeException("Failed to create volume");
|
||||
}
|
||||
volume = volumeApiService.createVolume(volume.getId(), null, null, pool.getId(), true);
|
||||
if (initialSize != null) {
|
||||
volumeDetailsDao.addDetail(volume.getId(), ApiConstants.VIRTUAL_SIZE, String.valueOf(initialSize), true);
|
||||
}
|
||||
|
||||
// Implementation for creating a Disk resource
|
||||
return VolumeJoinVOToDiskConverter.toDisk(volumeJoinDao.findById(volume.getId()));
|
||||
}
|
||||
|
||||
protected List<Nic> listNicsByInstance(final long instanceId, final String instanceUuid) {
|
||||
List<NicVO> nics = nicDao.listByVmId(instanceId);
|
||||
return NicVOToNicConverter.toNicList(nics, instanceUuid, this::getNetworkById);
|
||||
}
|
||||
|
||||
protected List<Nic> listNicsByInstance(final UserVmJoinVO vo) {
|
||||
return listNicsByInstance(vo.getId(), vo.getUuid());
|
||||
}
|
||||
|
||||
public List<Nic> listNicsByInstanceId(final String uuid) {
|
||||
UserVmVO vo = userVmDao.findByUuid(uuid);
|
||||
if (vo == null) {
|
||||
throw new InvalidParameterValueException("VM with ID " + uuid + " not found");
|
||||
}
|
||||
return listNicsByInstance(vo.getId(), vo.getUuid());
|
||||
}
|
||||
|
||||
public Nic handleVmAttachNic(final String vmUuid, final Nic request) {
|
||||
UserVmVO vmVo = userVmDao.findByUuid(vmUuid);
|
||||
if (vmVo == null) {
|
||||
throw new InvalidParameterValueException("VM with ID " + vmUuid + " not found");
|
||||
}
|
||||
if (request == null || request.getVnicProfile() == null || StringUtils.isEmpty(request.getVnicProfile().id)) {
|
||||
throw new InvalidParameterValueException("Request nic data is empty");
|
||||
}
|
||||
NetworkVO networkVO = networkDao.findByUuid(request.getVnicProfile().id);
|
||||
if (networkVO == null) {
|
||||
throw new InvalidParameterValueException("VNic profile " + request.getVnicProfile().id+ " not found");
|
||||
}
|
||||
Account serviceAccount = createServiceAccountIfNeeded();
|
||||
CallContext.register(serviceAccount.getId(), serviceAccount.getId());
|
||||
try {
|
||||
AddNicToVMCmd cmd = new AddNicToVMCmd();
|
||||
ComponentContext.inject(cmd);
|
||||
cmd.setVmId(vmVo.getId());
|
||||
cmd.setNetworkId(networkVO.getId());
|
||||
if (request.getMac() != null && StringUtils.isNotBlank(request.getMac().getAddress())) {
|
||||
cmd.setMacAddress(request.getMac().getAddress());
|
||||
}
|
||||
userVmService.addNicToVirtualMachine(cmd);
|
||||
NicVO nic = nicDao.findByInstanceIdAndNetworkIdIncludingRemoved(networkVO.getId(), vmVo.getId());
|
||||
if (nic == null) {
|
||||
throw new CloudRuntimeException("Failed to attach NIC to VM");
|
||||
}
|
||||
return NicVOToNicConverter.toNic(nic, vmUuid, this::getNetworkById);
|
||||
} finally {
|
||||
CallContext.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
public List<ImageTransfer> listAllImageTransfers() {
|
||||
List<ImageTransferVO> imageTransfers = imageTransferDao.listAll();
|
||||
return ImageTransferVOToImageTransferConverter.toImageTransferList(imageTransfers, this::getHostById, this::getVolumeById);
|
||||
}
|
||||
|
||||
public ImageTransfer getImageTransfer(String uuid) {
|
||||
ImageTransferVO vo = imageTransferDao.findByUuid(uuid);
|
||||
if (vo == null) {
|
||||
throw new InvalidParameterValueException("Image transfer with ID " + uuid + " not found");
|
||||
}
|
||||
return ImageTransferVOToImageTransferConverter.toImageTransfer(vo, this::getHostById, this::getVolumeById);
|
||||
}
|
||||
|
||||
public ImageTransfer handleCreateImageTransfer(ImageTransfer request) {
|
||||
if (request == null) {
|
||||
throw new InvalidParameterValueException("Request image transfer data is empty");
|
||||
}
|
||||
if (request.getDisk() == null || StringUtils.isBlank(request.getDisk().id)) {
|
||||
throw new InvalidParameterValueException("Disk ID must be specified");
|
||||
}
|
||||
VolumeJoinVO volumeVO = volumeJoinDao.findByUuid(request.getDisk().id);
|
||||
if (volumeVO == null) {
|
||||
throw new InvalidParameterValueException("Disk with ID " + request.getDisk().id + " not found");
|
||||
}
|
||||
Direction direction = EnumUtils.fromString(Direction.class, request.getDirection());
|
||||
if (direction == null) {
|
||||
throw new InvalidParameterValueException("Invalid or missing direction");
|
||||
}
|
||||
return createImageTransfer(null, volumeVO.getId(), direction);
|
||||
}
|
||||
|
||||
public boolean handleCancelImageTransfer(String uuid) {
|
||||
ImageTransferVO vo = imageTransferDao.findByUuid(uuid);
|
||||
if (vo == null) {
|
||||
throw new InvalidParameterValueException("Image transfer with ID " + uuid + " not found");
|
||||
}
|
||||
return incrementalBackupService.cancelImageTransfer(vo.getId());
|
||||
}
|
||||
|
||||
public boolean handleFinalizeImageTransfer(String uuid) {
|
||||
ImageTransferVO vo = imageTransferDao.findByUuid(uuid);
|
||||
if (vo == null) {
|
||||
throw new InvalidParameterValueException("Image transfer with ID " + uuid + " not found");
|
||||
}
|
||||
return incrementalBackupService.finalizeImageTransfer(vo.getId());
|
||||
}
|
||||
|
||||
private ImageTransfer createImageTransfer(Long backupId, Long volumeId, Direction direction) {
|
||||
Account serviceAccount = createServiceAccountIfNeeded();
|
||||
CallContext.register(serviceAccount.getId(), serviceAccount.getId());
|
||||
try {
|
||||
org.apache.cloudstack.backup.ImageTransfer imageTransfer =
|
||||
incrementalBackupService.createImageTransfer(volumeId, null, direction);
|
||||
ImageTransferVO imageTransferVO = imageTransferDao.findById(imageTransfer.getId());
|
||||
return ImageTransferVOToImageTransferConverter.toImageTransfer(imageTransferVO, this::getHostById, this::getVolumeById);
|
||||
} finally {
|
||||
CallContext.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
protected DataCenterJoinVO getZoneById(Long zoneId) {
|
||||
if (zoneId == null) {
|
||||
return null;
|
||||
}
|
||||
return dataCenterJoinDao.findById(zoneId);
|
||||
}
|
||||
|
||||
private HostJoinVO getHostById(Long hostId) {
|
||||
if (hostId == null) {
|
||||
return null;
|
||||
}
|
||||
return hostJoinDao.findById(hostId);
|
||||
}
|
||||
|
||||
private VolumeJoinVO getVolumeById(Long volumeId) {
|
||||
if (volumeId == null) {
|
||||
return null;
|
||||
}
|
||||
return volumeJoinDao.findById(volumeId);
|
||||
}
|
||||
|
||||
protected NetworkVO getNetworkById(Long networkId) {
|
||||
if (networkId == null) {
|
||||
return null;
|
||||
}
|
||||
return networkDao.findById(networkId);
|
||||
}
|
||||
|
||||
public List<Job> listAllJobs() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public Job getJob(String uuid) {
|
||||
// final ClusterVO vo = clusterDao.findByUuid(uuid);
|
||||
// if (vo == null) {
|
||||
// throw new InvalidParameterValueException("Cluster with ID " + uuid + " not found");
|
||||
// }
|
||||
long startTime = jobsMap.computeIfAbsent(uuid, k -> System.currentTimeMillis());
|
||||
long elapsed = System.currentTimeMillis() - startTime;
|
||||
if (elapsed > 10000L) {
|
||||
return AsyncJobJoinVOToJobConverter.toJob(uuid, "finished", startTime);
|
||||
} else {
|
||||
return AsyncJobJoinVOToJobConverter.toJob(uuid, "started", startTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,345 +0,0 @@
|
|||
// 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.adapter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.cloudstack.acl.Role;
|
||||
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.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd;
|
||||
import org.apache.cloudstack.api.command.user.network.ListNetworksCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.DeployVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.ListVMsCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.StartVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.StopVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.DeleteVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.ListVolumesCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
|
||||
import org.apache.cloudstack.backup.ImageTransfer.Direction;
|
||||
import org.apache.cloudstack.backup.ImageTransferVO;
|
||||
import org.apache.cloudstack.backup.IncrementalBackupService;
|
||||
import org.apache.cloudstack.backup.dao.ImageTransferDao;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||
import org.apache.cloudstack.veeam.api.converter.ImageTransferVOToImageTransferConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.VolumeJoinVOToDiskConverter;
|
||||
import org.apache.cloudstack.veeam.api.dto.Disk;
|
||||
import org.apache.cloudstack.veeam.api.dto.ImageTransfer;
|
||||
import org.apache.cloudstack.veeam.api.dto.Ref;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.cloud.api.query.dao.HostJoinDao;
|
||||
import com.cloud.api.query.dao.VolumeJoinDao;
|
||||
import com.cloud.api.query.vo.HostJoinVO;
|
||||
import com.cloud.api.query.vo.VolumeJoinVO;
|
||||
import com.cloud.dc.DataCenterVO;
|
||||
import com.cloud.dc.dao.DataCenterDao;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.hypervisor.Hypervisor;
|
||||
import com.cloud.org.Grouping;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.VolumeApiService;
|
||||
import com.cloud.storage.dao.VolumeDetailsDao;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountService;
|
||||
import com.cloud.user.AccountVO;
|
||||
import com.cloud.user.User;
|
||||
import com.cloud.user.UserAccount;
|
||||
import com.cloud.user.dao.AccountDao;
|
||||
import com.cloud.utils.EnumUtils;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
||||
public class UserResourceAdapter extends ManagerBase {
|
||||
private static final String SERVICE_ACCOUNT_NAME = "veemserviceuser";
|
||||
private static final String SERVICE_ACCOUNT_ROLE_NAME = "Veeam Service Role";
|
||||
private static final String SERVICE_ACCOUNT_FIRST_NAME = "Veeam";
|
||||
private static final String SERVICE_ACCOUNT_LAST_NAME = "Service User";
|
||||
private static final List<Class<?>> SERVICE_ACCOUNT_ROLE_ALLOWED_APIS = Arrays.asList(
|
||||
QueryAsyncJobResultCmd.class,
|
||||
ListVMsCmd.class,
|
||||
DeployVMCmd.class,
|
||||
StartVMCmd.class,
|
||||
StopVMCmd.class,
|
||||
DestroyVMCmd.class,
|
||||
ListVolumesCmd.class,
|
||||
CreateVolumeCmd.class,
|
||||
DeleteVolumeCmd.class,
|
||||
AttachVolumeCmd.class,
|
||||
DetachVolumeCmd.class,
|
||||
ResizeVolumeCmd.class,
|
||||
ListNetworksCmd.class
|
||||
);
|
||||
|
||||
@Inject
|
||||
DataCenterDao dataCenterDao;
|
||||
|
||||
@Inject
|
||||
RoleService roleService;
|
||||
|
||||
@Inject
|
||||
AccountService accountService;
|
||||
|
||||
@Inject
|
||||
AccountDao accountDao;
|
||||
|
||||
@Inject
|
||||
VolumeJoinDao volumeJoinDao;
|
||||
|
||||
@Inject
|
||||
VolumeDetailsDao volumeDetailsDao;
|
||||
|
||||
@Inject
|
||||
VolumeApiService volumeApiService;
|
||||
|
||||
@Inject
|
||||
PrimaryDataStoreDao primaryDataStoreDao;
|
||||
|
||||
@Inject
|
||||
ImageTransferDao imageTransferDao;
|
||||
|
||||
@Inject
|
||||
HostJoinDao hostJoinDao;
|
||||
|
||||
@Inject
|
||||
IncrementalBackupService incrementalBackupService;
|
||||
|
||||
protected Role createServiceAccountRole() {
|
||||
Role role = roleService.createRole(SERVICE_ACCOUNT_ROLE_NAME, RoleType.User,
|
||||
SERVICE_ACCOUNT_ROLE_NAME, false);
|
||||
for (Class<?> allowedApi : SERVICE_ACCOUNT_ROLE_ALLOWED_APIS) {
|
||||
final String apiName = BaseCmd.getCommandNameByClass(allowedApi);
|
||||
roleService.createRolePermission(role, new Rule(apiName), RolePermissionEntity.Permission.ALLOW,
|
||||
String.format("Allow %s", apiName));
|
||||
}
|
||||
roleService.createRolePermission(role, new Rule("*"), RolePermissionEntity.Permission.DENY,
|
||||
"Deny all");
|
||||
logger.debug("Created default role for Veeam service account in projects: {}", role);
|
||||
return role;
|
||||
}
|
||||
|
||||
public Role getServiceAccountRole() {
|
||||
List<Role> roles = roleService.findRolesByName(SERVICE_ACCOUNT_ROLE_NAME);
|
||||
if (CollectionUtils.isNotEmpty(roles)) {
|
||||
Role role = roles.get(0);
|
||||
logger.debug("Found default role for Veeam service account in projects: {}", role);
|
||||
return role;
|
||||
}
|
||||
return createServiceAccountRole();
|
||||
}
|
||||
|
||||
protected Account createServiceAccount() {
|
||||
CallContext.register(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM);
|
||||
try {
|
||||
Role role = getServiceAccountRole();
|
||||
UserAccount userAccount = accountService.createUserAccount(SERVICE_ACCOUNT_NAME,
|
||||
UUID.randomUUID().toString(), SERVICE_ACCOUNT_FIRST_NAME,
|
||||
SERVICE_ACCOUNT_LAST_NAME, null, null, SERVICE_ACCOUNT_NAME, Account.Type.NORMAL, role.getId(),
|
||||
1L, null, null, null, null, User.Source.NATIVE);
|
||||
Account account = accountService.getAccount(userAccount.getAccountId());
|
||||
logger.debug("Created Veeam service account: {}", account);
|
||||
return account;
|
||||
} finally {
|
||||
CallContext.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
protected Account createServiceAccountIfNeeded() {
|
||||
List<AccountVO> accounts = accountDao.findAccountsByName(SERVICE_ACCOUNT_NAME);
|
||||
for (AccountVO account : accounts) {
|
||||
if (Account.State.ENABLED.equals(account.getState())) {
|
||||
logger.debug("Veeam service account found: {}", account);
|
||||
return account;
|
||||
}
|
||||
}
|
||||
return createServiceAccount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean start() {
|
||||
createServiceAccountIfNeeded();
|
||||
//find public custom disk offering
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<Disk> listAllDisks() {
|
||||
List<VolumeJoinVO> kvmVolumes = volumeJoinDao.listByHypervisor(Hypervisor.HypervisorType.KVM);
|
||||
return VolumeJoinVOToDiskConverter.toDiskList(kvmVolumes);
|
||||
}
|
||||
|
||||
public Disk getDisk(String uuid) {
|
||||
VolumeJoinVO vo = volumeJoinDao.findByUuid(uuid);
|
||||
if (vo == null) {
|
||||
throw new InvalidParameterValueException("Disk with ID " + uuid + " not found");
|
||||
}
|
||||
return VolumeJoinVOToDiskConverter.toDisk(vo);
|
||||
}
|
||||
|
||||
public Disk handleCreateDisk(Disk request) {
|
||||
if (request == null) {
|
||||
throw new InvalidParameterValueException("Request disk data is empty");
|
||||
}
|
||||
String name = request.name;
|
||||
if (StringUtils.isBlank(name) && !name.startsWith("Veeam_KvmBackupDisk_")) {
|
||||
throw new InvalidParameterValueException("Only worker VM disk creation is supported");
|
||||
}
|
||||
if (request.storageDomains == null || CollectionUtils.isEmpty(request.storageDomains.storageDomain) ||
|
||||
request.storageDomains.storageDomain.size() > 1) {
|
||||
throw new InvalidParameterValueException("Exactly one storage domain must be specified");
|
||||
}
|
||||
Ref domain = request.storageDomains.storageDomain.get(0);
|
||||
if (domain == null || domain.id == null) {
|
||||
throw new InvalidParameterValueException("Storage domain ID must be specified");
|
||||
}
|
||||
StoragePoolVO pool = primaryDataStoreDao.findByUuid(domain.id);
|
||||
if (pool == null) {
|
||||
throw new InvalidParameterValueException("Storage domain with ID " + domain.id + " not found");
|
||||
}
|
||||
String sizeStr = request.provisionedSize;
|
||||
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");
|
||||
}
|
||||
provisionedSizeInGb = Math.max(1L, provisionedSizeInGb / (1024L * 1024L * 1024L));
|
||||
Long initialSize = null;
|
||||
if (StringUtils.isNotBlank(request.initialSize)) {
|
||||
try {
|
||||
initialSize = Long.parseLong(request.initialSize);
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
Account serviceAccount = createServiceAccountIfNeeded();
|
||||
DataCenterVO zone = dataCenterDao.findById(pool.getDataCenterId());
|
||||
if (zone == null || !Grouping.AllocationState.Enabled.equals(zone.getAllocationState())) {
|
||||
throw new InvalidParameterValueException("Datacenter for the specified storage domain is not found or not active");
|
||||
}
|
||||
Long diskOfferingId = volumeApiService.getCustomDiskOfferingIdForVolumeUpload(serviceAccount, zone);
|
||||
if (diskOfferingId == null) {
|
||||
throw new CloudRuntimeException("Failed to find custom offering for disk" + zone.getName());
|
||||
}
|
||||
CallContext.register(serviceAccount.getId(), serviceAccount.getId());
|
||||
try {
|
||||
return createDisk(serviceAccount, pool, name, diskOfferingId, provisionedSizeInGb, initialSize);
|
||||
} finally {
|
||||
CallContext.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Disk createDisk(Account serviceAccount, StoragePoolVO pool, String name, Long diskOfferingId, long sizeInGb, Long initialSize) {
|
||||
Volume volume;
|
||||
try {
|
||||
volume = volumeApiService.allocVolume(serviceAccount.getId(), pool.getDataCenterId(), diskOfferingId, null,
|
||||
null, name, sizeInGb, null, null, null, null);
|
||||
} catch (ResourceAllocationException e) {
|
||||
throw new CloudRuntimeException(e.getMessage(), e);
|
||||
}
|
||||
if (volume == null) {
|
||||
throw new CloudRuntimeException("Failed to create volume");
|
||||
}
|
||||
volume = volumeApiService.createVolume(volume.getId(), null, null, pool.getId(), true);
|
||||
if (initialSize != null) {
|
||||
volumeDetailsDao.addDetail(volume.getId(), ApiConstants.VIRTUAL_SIZE, String.valueOf(initialSize), true);
|
||||
}
|
||||
|
||||
// Implementation for creating a Disk resource
|
||||
return VolumeJoinVOToDiskConverter.toDisk(volumeJoinDao.findById(volume.getId()));
|
||||
}
|
||||
|
||||
public List<ImageTransfer> listAllImageTransfers() {
|
||||
List<ImageTransferVO> imageTransfers = imageTransferDao.listAll();
|
||||
return ImageTransferVOToImageTransferConverter.toImageTransferList(imageTransfers, this::getHostById, this::getVolumeById);
|
||||
}
|
||||
|
||||
private HostJoinVO getHostById(Long hostId) {
|
||||
if (hostId == null) {
|
||||
return null;
|
||||
}
|
||||
return hostJoinDao.findById(hostId);
|
||||
}
|
||||
|
||||
private VolumeJoinVO getVolumeById(Long volumeId) {
|
||||
if (volumeId == null) {
|
||||
return null;
|
||||
}
|
||||
return volumeJoinDao.findById(volumeId);
|
||||
}
|
||||
|
||||
public ImageTransfer getImageTransfer(String uuid) {
|
||||
ImageTransferVO vo = imageTransferDao.findByUuid(uuid);
|
||||
if (vo == null) {
|
||||
throw new InvalidParameterValueException("Image transfer with ID " + uuid + " not found");
|
||||
}
|
||||
return ImageTransferVOToImageTransferConverter.toImageTransfer(vo, this::getHostById, this::getVolumeById);
|
||||
}
|
||||
|
||||
public ImageTransfer handleCreateImageTransfer(ImageTransfer request) {
|
||||
if (request == null) {
|
||||
throw new InvalidParameterValueException("Request image transfer data is empty");
|
||||
}
|
||||
if (request.getDisk() == null || StringUtils.isBlank(request.getDisk().id)) {
|
||||
throw new InvalidParameterValueException("Disk ID must be specified");
|
||||
}
|
||||
VolumeJoinVO volumeVO = volumeJoinDao.findByUuid(request.getDisk().id);
|
||||
if (volumeVO == null) {
|
||||
throw new InvalidParameterValueException("Disk with ID " + request.getDisk().id + " not found");
|
||||
}
|
||||
Direction direction = EnumUtils.fromString(Direction.class, request.getDirection());
|
||||
if (direction == null) {
|
||||
throw new InvalidParameterValueException("Invalid or missing direction");
|
||||
}
|
||||
return createImageTransfer(null, volumeVO.getId(), direction);
|
||||
}
|
||||
|
||||
private ImageTransfer createImageTransfer(Long backupId, Long volumeId, Direction direction) {
|
||||
Account serviceAccount = createServiceAccountIfNeeded();
|
||||
CallContext.register(serviceAccount.getId(), serviceAccount.getId());
|
||||
try {
|
||||
org.apache.cloudstack.backup.ImageTransfer imageTransfer =
|
||||
incrementalBackupService.createImageTransfer(volumeId, null, direction);
|
||||
ImageTransferVO imageTransferVO = imageTransferDao.findById(imageTransfer.getId());
|
||||
return ImageTransferVOToImageTransferConverter.toImageTransfer(imageTransferVO, this::getHostById, this::getVolumeById);
|
||||
} finally {
|
||||
CallContext.unregister();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -32,13 +32,13 @@ import org.apache.cloudstack.veeam.RouteHandler;
|
|||
import org.apache.cloudstack.veeam.VeeamControlService;
|
||||
import org.apache.cloudstack.veeam.VeeamControlServlet;
|
||||
import org.apache.cloudstack.veeam.api.dto.Api;
|
||||
import org.apache.cloudstack.veeam.api.dto.ApiSummary;
|
||||
import org.apache.cloudstack.veeam.api.dto.EmptyElement;
|
||||
import org.apache.cloudstack.veeam.api.dto.Link;
|
||||
import org.apache.cloudstack.veeam.api.dto.ProductInfo;
|
||||
import org.apache.cloudstack.veeam.api.dto.Ref;
|
||||
import org.apache.cloudstack.veeam.api.dto.SpecialObjectRef;
|
||||
import org.apache.cloudstack.veeam.api.dto.SpecialObjects;
|
||||
import org.apache.cloudstack.veeam.api.dto.ApiSummary;
|
||||
import org.apache.cloudstack.veeam.api.dto.SummaryCount;
|
||||
import org.apache.cloudstack.veeam.api.dto.Version;
|
||||
import org.apache.cloudstack.veeam.utils.Negotiation;
|
||||
|
|
@ -65,7 +65,7 @@ public class ApiService extends ManagerBase implements RouteHandler {
|
|||
}
|
||||
|
||||
private void handleRootApiRequest(HttpServletRequest req, HttpServletResponse resp, Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
|
||||
io.getWriter().write(resp, 200,
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK,
|
||||
createDummyApi(VeeamControlService.ContextPath.value() + BASE_ROUTE),
|
||||
outFormat);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,27 +26,21 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.apache.cloudstack.veeam.RouteHandler;
|
||||
import org.apache.cloudstack.veeam.VeeamControlServlet;
|
||||
import org.apache.cloudstack.veeam.api.converter.ClusterVOToClusterConverter;
|
||||
import org.apache.cloudstack.veeam.adapter.ServerAdapter;
|
||||
import org.apache.cloudstack.veeam.api.dto.Cluster;
|
||||
import org.apache.cloudstack.veeam.api.dto.Clusters;
|
||||
import org.apache.cloudstack.veeam.utils.Negotiation;
|
||||
import org.apache.cloudstack.veeam.utils.PathUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import com.cloud.api.query.dao.DataCenterJoinDao;
|
||||
import com.cloud.api.query.vo.DataCenterJoinVO;
|
||||
import com.cloud.dc.ClusterVO;
|
||||
import com.cloud.dc.dao.ClusterDao;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
|
||||
public class ClustersRouteHandler extends ManagerBase implements RouteHandler {
|
||||
public static final String BASE_ROUTE = "/api/clusters";
|
||||
|
||||
@Inject
|
||||
ClusterDao clusterDao;
|
||||
|
||||
@Inject
|
||||
DataCenterJoinDao dataCenterJoinDao;
|
||||
ServerAdapter serverAdapter;
|
||||
|
||||
@Override
|
||||
public boolean start() {
|
||||
|
|
@ -90,32 +84,19 @@ 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 = ClusterVOToClusterConverter.toClusterList(listClusters(), this::getZoneById);
|
||||
final List<Cluster> result = serverAdapter.listAllClusters();
|
||||
final Clusters response = new Clusters(result);
|
||||
|
||||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
|
||||
protected List<ClusterVO> listClusters() {
|
||||
return clusterDao.listAll();
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
}
|
||||
|
||||
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
final ClusterVO vo = clusterDao.findByUuid(id);
|
||||
if (vo == null) {
|
||||
io.notFound(resp, "DataCenter not found: " + id, outFormat);
|
||||
return;
|
||||
try {
|
||||
Cluster response = serverAdapter.getCluster(id);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
} catch (InvalidParameterValueException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat);
|
||||
}
|
||||
Cluster response = ClusterVOToClusterConverter.toCluster(vo, this::getZoneById);
|
||||
|
||||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
|
||||
protected DataCenterJoinVO getZoneById(Long zoneId) {
|
||||
if (zoneId == null) {
|
||||
return null;
|
||||
}
|
||||
return dataCenterJoinDao.findById(zoneId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,9 +26,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.apache.cloudstack.veeam.RouteHandler;
|
||||
import org.apache.cloudstack.veeam.VeeamControlServlet;
|
||||
import org.apache.cloudstack.veeam.api.converter.DataCenterJoinVOToDataCenterConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.NetworkVOToNetworkConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.StoreVOToStorageDomainConverter;
|
||||
import org.apache.cloudstack.veeam.adapter.ServerAdapter;
|
||||
import org.apache.cloudstack.veeam.api.dto.DataCenter;
|
||||
import org.apache.cloudstack.veeam.api.dto.DataCenters;
|
||||
import org.apache.cloudstack.veeam.api.dto.Network;
|
||||
|
|
@ -39,33 +37,14 @@ import org.apache.cloudstack.veeam.utils.Negotiation;
|
|||
import org.apache.cloudstack.veeam.utils.PathUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import com.cloud.api.query.dao.DataCenterJoinDao;
|
||||
import com.cloud.api.query.dao.ImageStoreJoinDao;
|
||||
import com.cloud.api.query.dao.StoragePoolJoinDao;
|
||||
import com.cloud.api.query.vo.DataCenterJoinVO;
|
||||
import com.cloud.api.query.vo.ImageStoreJoinVO;
|
||||
import com.cloud.api.query.vo.StoragePoolJoinVO;
|
||||
import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.dao.NetworkVO;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
|
||||
public class DataCentersRouteHandler extends ManagerBase implements RouteHandler {
|
||||
public static final String BASE_ROUTE = "/api/datacenters";
|
||||
private static final int DEFAULT_MAX = 50;
|
||||
private static final int HARD_CAP_MAX = 1000;
|
||||
private static final int DEFAULT_PAGE = 1;
|
||||
|
||||
@Inject
|
||||
DataCenterJoinDao dataCenterJoinDao;
|
||||
|
||||
@Inject
|
||||
StoragePoolJoinDao storagePoolJoinDao;
|
||||
|
||||
@Inject
|
||||
ImageStoreJoinDao imageStoreJoinDao;
|
||||
|
||||
@Inject
|
||||
NetworkDao networkDao;
|
||||
ServerAdapter serverAdapter;
|
||||
|
||||
@Override
|
||||
public boolean start() {
|
||||
|
|
@ -119,66 +98,41 @@ 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 = DataCenterJoinVOToDataCenterConverter.toDCList(listDCs());
|
||||
final List<DataCenter> result = serverAdapter.listAllDataCenters();
|
||||
final DataCenters response = new DataCenters(result);
|
||||
|
||||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
|
||||
protected List<DataCenterJoinVO> listDCs() {
|
||||
return dataCenterJoinDao.listAll();
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
}
|
||||
|
||||
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
final DataCenterJoinVO dataCenterVO = dataCenterJoinDao.findByUuid(id);
|
||||
if (dataCenterVO == null) {
|
||||
io.notFound(resp, "DataCenter not found: " + id, outFormat);
|
||||
return;
|
||||
try {
|
||||
DataCenter response = serverAdapter.getDataCenter(id);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
} catch (InvalidParameterValueException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat);
|
||||
}
|
||||
DataCenter response = DataCenterJoinVOToDataCenterConverter.toDataCenter(dataCenterVO);
|
||||
|
||||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
|
||||
protected List<StoragePoolJoinVO> listStoragePoolsByDcId(final long dcId) {
|
||||
return storagePoolJoinDao.listAll();
|
||||
}
|
||||
|
||||
protected List<ImageStoreJoinVO> listImageStoresByDcId(final long dcId) {
|
||||
return imageStoreJoinDao.listAll();
|
||||
}
|
||||
|
||||
protected List<NetworkVO> listNetworksByDcId(final long dcId) {
|
||||
return networkDao.listAll();
|
||||
}
|
||||
|
||||
protected void handleGetStorageDomainsByDcId(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
final DataCenterJoinVO dataCenterVO = dataCenterJoinDao.findByUuid(id);
|
||||
if (dataCenterVO == null) {
|
||||
io.notFound(resp, "DataCenter not found: " + id, outFormat);
|
||||
return;
|
||||
try {
|
||||
List<StorageDomain> storageDomains = serverAdapter.listStorageDomainsByDcId(id);
|
||||
StorageDomains response = new StorageDomains(storageDomains);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
} catch (InvalidParameterValueException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat);
|
||||
}
|
||||
List<StorageDomain> storageDomains = StoreVOToStorageDomainConverter.toStorageDomainListFromPools(listStoragePoolsByDcId(dataCenterVO.getId()));
|
||||
storageDomains.addAll(StoreVOToStorageDomainConverter.toStorageDomainListFromStores(listImageStoresByDcId(dataCenterVO.getId())));
|
||||
|
||||
StorageDomains response = new StorageDomains(storageDomains);
|
||||
|
||||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
|
||||
protected void handleGetNetworksByDcId(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
final DataCenterJoinVO dataCenterVO = dataCenterJoinDao.findByUuid(id);
|
||||
if (dataCenterVO == null) {
|
||||
io.notFound(resp, "DataCenter not found: " + id, outFormat);
|
||||
return;
|
||||
try {
|
||||
List<Network> networks = serverAdapter.listNetworksByDcId(id);
|
||||
Networks response = new Networks(networks);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
} catch (InvalidParameterValueException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat);
|
||||
}
|
||||
List<Network> networks = NetworkVOToNetworkConverter.toNetworkList(listNetworksByDcId(dataCenterVO.getId()), (dcId) -> dataCenterVO);
|
||||
|
||||
Networks response = new Networks(networks);
|
||||
|
||||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.apache.cloudstack.veeam.RouteHandler;
|
||||
import org.apache.cloudstack.veeam.VeeamControlServlet;
|
||||
import org.apache.cloudstack.veeam.adapter.UserResourceAdapter;
|
||||
import org.apache.cloudstack.veeam.adapter.ServerAdapter;
|
||||
import org.apache.cloudstack.veeam.api.dto.Disk;
|
||||
import org.apache.cloudstack.veeam.api.dto.Disks;
|
||||
import org.apache.cloudstack.veeam.utils.Negotiation;
|
||||
|
|
@ -42,7 +42,7 @@ public class DisksRouteHandler extends ManagerBase implements RouteHandler {
|
|||
public static final String BASE_ROUTE = "/api/disks";
|
||||
|
||||
@Inject
|
||||
UserResourceAdapter userResourceAdapter;
|
||||
ServerAdapter serverAdapter;
|
||||
|
||||
@Override
|
||||
public boolean start() {
|
||||
|
|
@ -74,16 +74,22 @@ public class DisksRouteHandler extends ManagerBase implements RouteHandler {
|
|||
}
|
||||
}
|
||||
|
||||
if (!"GET".equalsIgnoreCase(method)) {
|
||||
io.methodNotAllowed(resp, "GET", outFormat);
|
||||
return;
|
||||
}
|
||||
List<String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
|
||||
if (CollectionUtils.isNotEmpty(idAndSubPath)) {
|
||||
String id = idAndSubPath.get(0);
|
||||
if (idAndSubPath.size() == 1) {
|
||||
handleGetById(id, resp, outFormat, io);
|
||||
return;
|
||||
if (!"GET".equalsIgnoreCase(method) && !"DELETE".equalsIgnoreCase(method)) {
|
||||
io.methodNotAllowed(resp, "GET, DELETE", outFormat);
|
||||
return;
|
||||
}
|
||||
if ("GET".equalsIgnoreCase(method)) {
|
||||
handleGetById(id, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
if ("DELETE".equalsIgnoreCase(method)) {
|
||||
handleDeleteById(id, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -92,32 +98,42 @@ 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 = userResourceAdapter.listAllDisks();
|
||||
final List<Disk> result = serverAdapter.listAllDisks();
|
||||
final Disks response = new Disks(result);
|
||||
|
||||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
}
|
||||
|
||||
protected void handlePost(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
|
||||
String data = RouteHandler.getRequestData(req);
|
||||
logger.info("Received POST request on /api/disks endpoint, but method: POST is not supported atm. Request-data: {}", data);
|
||||
logger.info("Received POST request on /api/disks endpoint. Request-data: {}", data); // ToDo: remove
|
||||
try {
|
||||
Disk request = io.getMapper().jsonMapper().readValue(data, Disk.class);
|
||||
Disk response = userResourceAdapter.handleCreateDisk(request);
|
||||
io.getWriter().write(resp, 201, response, outFormat);
|
||||
Disk response = serverAdapter.handleCreateDisk(request);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_CREATED, response, outFormat);
|
||||
} catch (JsonProcessingException | CloudRuntimeException e) {
|
||||
io.getWriter().write(resp, 400, e.getMessage(), outFormat);
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_BAD_REQUEST, "Bad request", e.getMessage(), outFormat);
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
try {
|
||||
Disk response = userResourceAdapter.getDisk(id);
|
||||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
Disk response = serverAdapter.getDisk(id);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
} catch (InvalidParameterValueException e) {
|
||||
io.getWriter().write(resp, 404, e.getMessage(), outFormat);
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat);
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleDeleteById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
try {
|
||||
serverAdapter.deleteDisk(id);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, "Deleted disk ID: " + id, outFormat);
|
||||
} catch (InvalidParameterValueException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_BAD_REQUEST, "Bad request", e.getMessage(), outFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,22 +26,21 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.apache.cloudstack.veeam.RouteHandler;
|
||||
import org.apache.cloudstack.veeam.VeeamControlServlet;
|
||||
import org.apache.cloudstack.veeam.api.converter.HostJoinVOToHostConverter;
|
||||
import org.apache.cloudstack.veeam.adapter.ServerAdapter;
|
||||
import org.apache.cloudstack.veeam.api.dto.Host;
|
||||
import org.apache.cloudstack.veeam.api.dto.Hosts;
|
||||
import org.apache.cloudstack.veeam.utils.Negotiation;
|
||||
import org.apache.cloudstack.veeam.utils.PathUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import com.cloud.api.query.dao.HostJoinDao;
|
||||
import com.cloud.api.query.vo.HostJoinVO;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
|
||||
public class HostsRouteHandler extends ManagerBase implements RouteHandler {
|
||||
public static final String BASE_ROUTE = "/api/hosts";
|
||||
|
||||
@Inject
|
||||
HostJoinDao hostJoinDao;
|
||||
ServerAdapter serverAdapter;
|
||||
|
||||
@Override
|
||||
public boolean start() {
|
||||
|
|
@ -85,25 +84,19 @@ 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 = HostJoinVOToHostConverter.toHostList(listHosts());
|
||||
final List<Host> result = serverAdapter.listAllHosts();
|
||||
final Hosts response = new Hosts(result);
|
||||
|
||||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
|
||||
protected List<HostJoinVO> listHosts() {
|
||||
return hostJoinDao.listAll();
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
}
|
||||
|
||||
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
final HostJoinVO vo = hostJoinDao.findByUuid(id);
|
||||
if (vo == null) {
|
||||
io.notFound(resp, "DataCenter not found: " + id, outFormat);
|
||||
return;
|
||||
try {
|
||||
Host response = serverAdapter.getHost(id);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
} catch (InvalidParameterValueException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat);
|
||||
}
|
||||
Host response = HostJoinVOToHostConverter.toHost(vo);
|
||||
|
||||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.apache.cloudstack.veeam.RouteHandler;
|
||||
import org.apache.cloudstack.veeam.VeeamControlServlet;
|
||||
import org.apache.cloudstack.veeam.adapter.UserResourceAdapter;
|
||||
import org.apache.cloudstack.veeam.adapter.ServerAdapter;
|
||||
import org.apache.cloudstack.veeam.api.dto.ImageTransfer;
|
||||
import org.apache.cloudstack.veeam.api.dto.ImageTransfers;
|
||||
import org.apache.cloudstack.veeam.utils.Negotiation;
|
||||
|
|
@ -42,7 +42,7 @@ public class ImageTransfersRouteHandler extends ManagerBase implements RouteHand
|
|||
public static final String BASE_ROUTE = "/api/imagetransfers";
|
||||
|
||||
@Inject
|
||||
UserResourceAdapter userResourceAdapter;
|
||||
ServerAdapter serverAdapter;
|
||||
|
||||
@Override
|
||||
public boolean start() {
|
||||
|
|
@ -105,11 +105,10 @@ 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 = userResourceAdapter.listAllImageTransfers();
|
||||
final List<ImageTransfer> result = serverAdapter.listAllImageTransfers();
|
||||
final ImageTransfers response = new ImageTransfers();
|
||||
response.setImageTransfer(result);
|
||||
|
||||
io.getWriter().write(resp, 400, response, outFormat);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
}
|
||||
|
||||
protected void handlePost(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
|
|
@ -118,32 +117,40 @@ public class ImageTransfersRouteHandler extends ManagerBase implements RouteHand
|
|||
logger.info("Received POST request on /api/imagetransfers endpoint. Request-data: {}", data);
|
||||
try {
|
||||
ImageTransfer request = io.getMapper().jsonMapper().readValue(data, ImageTransfer.class);
|
||||
ImageTransfer response = userResourceAdapter.handleCreateImageTransfer(request);
|
||||
io.getWriter().write(resp, 201, response, outFormat);
|
||||
ImageTransfer response = serverAdapter.handleCreateImageTransfer(request);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_CREATED, response, outFormat);
|
||||
} catch (JsonProcessingException | CloudRuntimeException e) {
|
||||
io.getWriter().write(resp, 400, e.getMessage(), outFormat);
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_BAD_REQUEST, "Bad Request", e.getMessage(), outFormat);
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
try {
|
||||
ImageTransfer response = userResourceAdapter.getImageTransfer(id);
|
||||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
ImageTransfer response = serverAdapter.getImageTransfer(id);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
} catch (InvalidParameterValueException e) {
|
||||
io.getWriter().write(resp, 404, e.getMessage(), outFormat);
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat);
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleCancelById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
//ToDo: implement cancel logic
|
||||
io.getWriter().write(resp, 200, "Image transfer cancelled successfully", outFormat);
|
||||
try {
|
||||
serverAdapter.handleCancelImageTransfer(id);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, "Image transfer cancelled successfully", outFormat);
|
||||
} catch (InvalidParameterValueException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat);
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleFinalizeById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
//ToDo: implement finalize logic
|
||||
io.getWriter().write(resp, 200, "Image transfer finalized successfully", outFormat);
|
||||
try {
|
||||
serverAdapter.handleFinalizeImageTransfer(id);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, "Image transfer finalized successfully", outFormat);
|
||||
} catch (CloudRuntimeException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 org.apache.cloudstack.veeam.api;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.cloudstack.veeam.RouteHandler;
|
||||
import org.apache.cloudstack.veeam.VeeamControlServlet;
|
||||
import org.apache.cloudstack.veeam.adapter.ServerAdapter;
|
||||
import org.apache.cloudstack.veeam.api.dto.Job;
|
||||
import org.apache.cloudstack.veeam.api.dto.Jobs;
|
||||
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.utils.component.ManagerBase;
|
||||
|
||||
public class JobsRouteHandler extends ManagerBase implements RouteHandler {
|
||||
public static final String BASE_ROUTE = "/api/jobs";
|
||||
|
||||
@Inject
|
||||
ServerAdapter serverAdapter;
|
||||
|
||||
@Override
|
||||
public boolean start() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int priority() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canHandle(String method, String path) {
|
||||
return getSanitizedPath(path).startsWith(BASE_ROUTE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(HttpServletRequest req, HttpServletResponse resp, String path, Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
|
||||
final String method = req.getMethod();
|
||||
if (!"GET".equalsIgnoreCase(method)) {
|
||||
io.methodNotAllowed(resp, "GET", outFormat);
|
||||
return;
|
||||
}
|
||||
final String sanitizedPath = getSanitizedPath(path);
|
||||
if (sanitizedPath.equals(BASE_ROUTE)) {
|
||||
handleGet(req, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
|
||||
if (CollectionUtils.isNotEmpty(idAndSubPath)) {
|
||||
String id = idAndSubPath.get(0);
|
||||
if (idAndSubPath.size() == 1) {
|
||||
handleGetById(id, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found");
|
||||
}
|
||||
|
||||
protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
|
||||
final List<Job> result = serverAdapter.listAllJobs();
|
||||
final Jobs response = new Jobs(result);
|
||||
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
}
|
||||
|
||||
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
try {
|
||||
Job response = serverAdapter.getJob(id);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
} catch (InvalidParameterValueException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -26,27 +26,21 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.apache.cloudstack.veeam.RouteHandler;
|
||||
import org.apache.cloudstack.veeam.VeeamControlServlet;
|
||||
import org.apache.cloudstack.veeam.api.converter.NetworkVOToNetworkConverter;
|
||||
import org.apache.cloudstack.veeam.adapter.ServerAdapter;
|
||||
import org.apache.cloudstack.veeam.api.dto.Network;
|
||||
import org.apache.cloudstack.veeam.api.dto.Networks;
|
||||
import org.apache.cloudstack.veeam.utils.Negotiation;
|
||||
import org.apache.cloudstack.veeam.utils.PathUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import com.cloud.api.query.dao.DataCenterJoinDao;
|
||||
import com.cloud.api.query.vo.DataCenterJoinVO;
|
||||
import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.dao.NetworkVO;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
|
||||
public class NetworksRouteHandler extends ManagerBase implements RouteHandler {
|
||||
public static final String BASE_ROUTE = "/api/networks";
|
||||
|
||||
@Inject
|
||||
NetworkDao networkDao;
|
||||
|
||||
@Inject
|
||||
DataCenterJoinDao dataCenterJoinDao;
|
||||
ServerAdapter serverAdapter;
|
||||
|
||||
@Override
|
||||
public boolean start() {
|
||||
|
|
@ -90,32 +84,19 @@ 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 = NetworkVOToNetworkConverter.toNetworkList(listNetworks(), this::getZoneById);
|
||||
final List<Network> result = serverAdapter.listAllNetworks();
|
||||
final Networks response = new Networks(result);
|
||||
|
||||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
|
||||
protected List<NetworkVO> listNetworks() {
|
||||
return networkDao.listAll();
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
}
|
||||
|
||||
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
final NetworkVO vo = networkDao.findByUuid(id);
|
||||
if (vo == null) {
|
||||
io.notFound(resp, "DataCenter not found: " + id, outFormat);
|
||||
return;
|
||||
try {
|
||||
Network response = serverAdapter.getNetwork(id);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
} catch (InvalidParameterValueException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat);
|
||||
}
|
||||
Network response = NetworkVOToNetworkConverter.toNetwork(vo, this::getZoneById);
|
||||
|
||||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
|
||||
protected DataCenterJoinVO getZoneById(Long zoneId) {
|
||||
if (zoneId == null) {
|
||||
return null;
|
||||
}
|
||||
return dataCenterJoinDao.findById(zoneId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,27 +27,26 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.apache.cloudstack.veeam.RouteHandler;
|
||||
import org.apache.cloudstack.veeam.VeeamControlServlet;
|
||||
import org.apache.cloudstack.veeam.api.converter.UserVmJoinVOToVmConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.VolumeJoinVOToDiskConverter;
|
||||
import org.apache.cloudstack.veeam.adapter.ServerAdapter;
|
||||
import org.apache.cloudstack.veeam.api.dto.DiskAttachment;
|
||||
import org.apache.cloudstack.veeam.api.dto.DiskAttachments;
|
||||
import org.apache.cloudstack.veeam.api.dto.Nic;
|
||||
import org.apache.cloudstack.veeam.api.dto.Nics;
|
||||
import org.apache.cloudstack.veeam.api.dto.Vm;
|
||||
import org.apache.cloudstack.veeam.api.dto.VmAction;
|
||||
import org.apache.cloudstack.veeam.api.dto.Vms;
|
||||
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.response.VmCollectionResponse;
|
||||
import org.apache.cloudstack.veeam.api.response.VmEntityResponse;
|
||||
import org.apache.cloudstack.veeam.utils.Negotiation;
|
||||
import org.apache.cloudstack.veeam.utils.PathUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import com.cloud.api.query.dao.HostJoinDao;
|
||||
import com.cloud.api.query.dao.UserVmJoinDao;
|
||||
import com.cloud.api.query.dao.VolumeJoinDao;
|
||||
import com.cloud.api.query.vo.HostJoinVO;
|
||||
import com.cloud.api.query.vo.UserVmJoinVO;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
|
||||
public class VmsRouteHandler extends ManagerBase implements RouteHandler {
|
||||
public static final String BASE_ROUTE = "/api/vms";
|
||||
|
|
@ -56,13 +55,7 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler {
|
|||
private static final int DEFAULT_PAGE = 1;
|
||||
|
||||
@Inject
|
||||
UserVmJoinDao userVmJoinDao;
|
||||
|
||||
@Inject
|
||||
HostJoinDao hostJoinDao;
|
||||
|
||||
@Inject
|
||||
VolumeJoinDao volumeJoinDao;
|
||||
ServerAdapter serverAdapter;
|
||||
|
||||
private VmSearchParser searchParser;
|
||||
|
||||
|
|
@ -90,24 +83,74 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler {
|
|||
final String method = req.getMethod();
|
||||
final String sanitizedPath = getSanitizedPath(path);
|
||||
if (sanitizedPath.equals(BASE_ROUTE)) {
|
||||
if (!"GET".equalsIgnoreCase(method)) {
|
||||
io.methodNotAllowed(resp, "GET", outFormat);
|
||||
if (!"GET".equalsIgnoreCase(method) && !"POST".equalsIgnoreCase(method) && !"DELETE".equalsIgnoreCase(method)) {
|
||||
io.methodNotAllowed(resp, "GET, POST, DELETE", outFormat);
|
||||
return;
|
||||
}
|
||||
if ("GET".equalsIgnoreCase(method)) {
|
||||
handleGet(req, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
if ("POST".equalsIgnoreCase(method)) {
|
||||
handlePost(req, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
handleGet(req, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
|
||||
if (CollectionUtils.isNotEmpty(idAndSubPath)) {
|
||||
String id = idAndSubPath.get(0);
|
||||
if (idAndSubPath.size() == 1) {
|
||||
handleGetById(id, resp, outFormat, io);
|
||||
if (!"GET".equalsIgnoreCase(method) && !"PUT".equalsIgnoreCase(method) && !"DELETE".equalsIgnoreCase(method)) {
|
||||
io.methodNotAllowed(resp, "GET, PUT, DELETE", outFormat);
|
||||
} else if ("GET".equalsIgnoreCase(method)) {
|
||||
handleGetById(id, resp, outFormat, io);
|
||||
} else if ("DELETE".equalsIgnoreCase(method)) {
|
||||
handleUpdateById(id, req, resp, outFormat, io);
|
||||
} else if ("DELETE".equalsIgnoreCase(method)) {
|
||||
handleDeleteById(id, resp, outFormat, io);
|
||||
}
|
||||
return;
|
||||
} else if (idAndSubPath.size() == 2) {
|
||||
String subPath = idAndSubPath.get(1);
|
||||
if ("diskattachments".equals(subPath)) {
|
||||
handleGetDisAttachmentsByVmId(id, resp, outFormat, io);
|
||||
if ("start".equals(subPath)) {
|
||||
if ("POST".equalsIgnoreCase(method)) {
|
||||
handleStartVmById(id, req, resp, outFormat, io);
|
||||
} else {
|
||||
io.methodNotAllowed(resp, "POST", outFormat);
|
||||
}
|
||||
return;
|
||||
} else if ("stop".equals(subPath)) {
|
||||
if ("POST".equalsIgnoreCase(method)) {
|
||||
handleStopVmById(id, req, resp, outFormat, io);
|
||||
} else {
|
||||
io.methodNotAllowed(resp, "POST", outFormat);
|
||||
}
|
||||
return;
|
||||
} else if ("shutdown".equals(subPath)) {
|
||||
if ("POST".equalsIgnoreCase(method)) {
|
||||
handleShutdownVmById(id, req, resp, outFormat, io);
|
||||
} else {
|
||||
io.methodNotAllowed(resp, "POST", outFormat);
|
||||
}
|
||||
return;
|
||||
} else if ("diskattachments".equals(subPath)) {
|
||||
if (!"GET".equalsIgnoreCase(method) && !"POST".equalsIgnoreCase(method)) {
|
||||
io.methodNotAllowed(resp, "GET, POST", outFormat);
|
||||
} else if ("GET".equalsIgnoreCase(method)) {
|
||||
handleGetDiskAttachmentsByVmId(id, resp, outFormat, io);
|
||||
} else if ("POST".equalsIgnoreCase(method)) {
|
||||
handlePostDiskAttachmentForVmId(id, req, resp, outFormat, io);
|
||||
}
|
||||
return;
|
||||
} else if ("nics".equals(subPath)) {
|
||||
if (!"GET".equalsIgnoreCase(method) && !"POST".equalsIgnoreCase(method)) {
|
||||
io.methodNotAllowed(resp, "GET, POST", outFormat);
|
||||
} else if ("GET".equalsIgnoreCase(method)) {
|
||||
handleGetNicsByVmId(id, resp, outFormat, io);
|
||||
} else if ("POST".equalsIgnoreCase(method)) {
|
||||
handlePostNicForVmId(id, req, resp, outFormat, io);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -149,10 +192,10 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler {
|
|||
return;
|
||||
}
|
||||
|
||||
final List<Vm> result = UserVmJoinVOToVmConverter.toVmList(listUserVms(), this::getHostById);
|
||||
final VmCollectionResponse response = new VmCollectionResponse(result);
|
||||
final List<Vm> result = serverAdapter.listAllUserVms();
|
||||
final Vms response = new Vms(result);
|
||||
|
||||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
}
|
||||
|
||||
protected static VmListQuery fromRequest(final HttpServletRequest req) {
|
||||
|
|
@ -172,41 +215,123 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler {
|
|||
}
|
||||
}
|
||||
|
||||
protected List<UserVmJoinVO> listUserVms() {
|
||||
// Todo: add filtering, pagination
|
||||
return userVmJoinDao.listAll();
|
||||
protected void handlePost(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
|
||||
String data = RouteHandler.getRequestData(req);
|
||||
logger.info("Received method: POST request. Request-data: {}", data);
|
||||
try {
|
||||
Vm request = io.getMapper().jsonMapper().readValue(data, Vm.class);
|
||||
Vm response = serverAdapter.handleCreateVm(request);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_CREATED, response, outFormat);
|
||||
} catch (JsonProcessingException | CloudRuntimeException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_BAD_REQUEST, "Bad request", e.getMessage(), outFormat);
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
final UserVmJoinVO userVmJoinVO = userVmJoinDao.findByUuid(id);
|
||||
if (userVmJoinVO == null) {
|
||||
io.notFound(resp, "VM not found: " + id, outFormat);
|
||||
return;
|
||||
try {
|
||||
Vm response = serverAdapter.getVm(id);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
} catch (InvalidParameterValueException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat);
|
||||
}
|
||||
VmEntityResponse response = new VmEntityResponse(UserVmJoinVOToVmConverter.toVm(userVmJoinVO, this::getHostById));
|
||||
|
||||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
|
||||
protected void handleGetDisAttachmentsByVmId(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
final UserVmJoinVO userVmJoinVO = userVmJoinDao.findByUuid(id);
|
||||
if (userVmJoinVO == null) {
|
||||
io.notFound(resp, "VM not found: " + id, outFormat);
|
||||
return;
|
||||
}
|
||||
List<DiskAttachment> disks = VolumeJoinVOToDiskConverter.toDiskAttachmentList(
|
||||
volumeJoinDao.listByInstanceId(userVmJoinVO.getId()));
|
||||
DiskAttachments response = new DiskAttachments(disks);
|
||||
|
||||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
protected void handleUpdateById(final String id, final HttpServletRequest req, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
String data = RouteHandler.getRequestData(req);
|
||||
logger.info("Received POST request, but method: POST is not supported atm. Request-data: {}", data);
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_BAD_REQUEST, "Not implemented", "", outFormat);
|
||||
}
|
||||
|
||||
protected HostJoinVO getHostById(Long hostId) {
|
||||
if (hostId == null) {
|
||||
return null;
|
||||
protected void handleDeleteById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
try {
|
||||
serverAdapter.deleteVm(id);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, "", outFormat);
|
||||
} catch (CloudRuntimeException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat);
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleStartVmById(final String id, final HttpServletRequest req, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
try {
|
||||
VmAction vm = serverAdapter.startVm(id);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_ACCEPTED, vm, outFormat);
|
||||
} catch (CloudRuntimeException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat);
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleStopVmById(final String id, final HttpServletRequest req, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
try {
|
||||
VmAction vm = serverAdapter.stopVm(id);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_ACCEPTED, vm, outFormat);
|
||||
} catch (CloudRuntimeException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat);
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleShutdownVmById(final String id, final HttpServletRequest req, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
try {
|
||||
VmAction vm = serverAdapter.shutdownVm(id);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_ACCEPTED, vm, outFormat);
|
||||
} catch (CloudRuntimeException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat);
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleGetDiskAttachmentsByVmId(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
try {
|
||||
List<DiskAttachment> disks = serverAdapter.listDiskAttachmentsByInstanceUuid(id);
|
||||
DiskAttachments response = new DiskAttachments(disks);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
} catch (InvalidParameterValueException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat);
|
||||
}
|
||||
}
|
||||
|
||||
protected void handlePostDiskAttachmentForVmId(final String id, final HttpServletRequest req,
|
||||
final HttpServletResponse resp, final Negotiation.OutFormat outFormat, final VeeamControlServlet io)
|
||||
throws IOException {
|
||||
String data = RouteHandler.getRequestData(req);
|
||||
logger.info("Received method: POST request. Request-data: {}", data);
|
||||
try {
|
||||
DiskAttachment request = io.getMapper().jsonMapper().readValue(data, DiskAttachment.class);
|
||||
DiskAttachment response = serverAdapter.handleVmAttachDisk(id, request);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_CREATED, response, outFormat);
|
||||
} catch (JsonProcessingException | CloudRuntimeException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_BAD_REQUEST, "Bad request", e.getMessage(), outFormat);
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleGetNicsByVmId(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
try {
|
||||
List<Nic> nics = serverAdapter.listNicsByInstanceId(id);
|
||||
Nics response = new Nics(nics);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
} catch (InvalidParameterValueException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat);
|
||||
}
|
||||
}
|
||||
|
||||
protected void handlePostNicForVmId(final String id, final HttpServletRequest req,
|
||||
final HttpServletResponse resp, final Negotiation.OutFormat outFormat, final VeeamControlServlet io)
|
||||
throws IOException {
|
||||
String data = RouteHandler.getRequestData(req);
|
||||
logger.info("Received method: POST request. Request-data: {}", data);
|
||||
try {
|
||||
Nic request = io.getMapper().jsonMapper().readValue(data, Nic.class);
|
||||
Nic response = serverAdapter.handleVmAttachNic(id, request);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_CREATED, response, outFormat);
|
||||
} catch (JsonProcessingException | CloudRuntimeException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_BAD_REQUEST, "Bad request", e.getMessage(), outFormat);
|
||||
}
|
||||
return hostJoinDao.findById(hostId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,27 +26,21 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.apache.cloudstack.veeam.RouteHandler;
|
||||
import org.apache.cloudstack.veeam.VeeamControlServlet;
|
||||
import org.apache.cloudstack.veeam.api.converter.NetworkVOToVnicProfileConverter;
|
||||
import org.apache.cloudstack.veeam.adapter.ServerAdapter;
|
||||
import org.apache.cloudstack.veeam.api.dto.VnicProfile;
|
||||
import org.apache.cloudstack.veeam.api.dto.VnicProfiles;
|
||||
import org.apache.cloudstack.veeam.utils.Negotiation;
|
||||
import org.apache.cloudstack.veeam.utils.PathUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import com.cloud.api.query.dao.DataCenterJoinDao;
|
||||
import com.cloud.api.query.vo.DataCenterJoinVO;
|
||||
import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.dao.NetworkVO;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
|
||||
public class VnicProfilesRouteHandler extends ManagerBase implements RouteHandler {
|
||||
public static final String BASE_ROUTE = "/api/vnicprofiles";
|
||||
|
||||
@Inject
|
||||
NetworkDao networkDao;
|
||||
|
||||
@Inject
|
||||
DataCenterJoinDao dataCenterJoinDao;
|
||||
ServerAdapter serverAdapter;
|
||||
|
||||
@Override
|
||||
public boolean start() {
|
||||
|
|
@ -90,32 +84,19 @@ 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 = NetworkVOToVnicProfileConverter.toVnicProfileList(listNetworks(), this::getZoneById);
|
||||
final List<VnicProfile> result = serverAdapter.listAllVnicProfiles();
|
||||
final VnicProfiles response = new VnicProfiles(result);
|
||||
|
||||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
|
||||
protected List<NetworkVO> listNetworks() {
|
||||
return networkDao.listAll();
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
}
|
||||
|
||||
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
final NetworkVO vo = networkDao.findByUuid(id);
|
||||
if (vo == null) {
|
||||
io.notFound(resp, "DataCenter not found: " + id, outFormat);
|
||||
return;
|
||||
try {
|
||||
VnicProfile response = serverAdapter.getVnicProfile(id);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
} catch (InvalidParameterValueException e) {
|
||||
io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat);
|
||||
}
|
||||
VnicProfile response = NetworkVOToVnicProfileConverter.toVnicProfile(vo, this::getZoneById);
|
||||
|
||||
io.getWriter().write(resp, 200, response, outFormat);
|
||||
}
|
||||
|
||||
protected DataCenterJoinVO getZoneById(Long zoneId) {
|
||||
if (zoneId == null) {
|
||||
return null;
|
||||
}
|
||||
return dataCenterJoinDao.findById(zoneId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
// 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.converter;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.cloudstack.veeam.VeeamControlService;
|
||||
import org.apache.cloudstack.veeam.api.JobsRouteHandler;
|
||||
import org.apache.cloudstack.veeam.api.dto.Actions;
|
||||
import org.apache.cloudstack.veeam.api.dto.Job;
|
||||
import org.apache.cloudstack.veeam.api.dto.Ref;
|
||||
|
||||
public class AsyncJobJoinVOToJobConverter {
|
||||
|
||||
public static Job toJob(String uuid, String state, long startTime) {
|
||||
Job job = new Job();
|
||||
final String basePath = VeeamControlService.ContextPath.value();
|
||||
// Fill in dummy data for now, as the AsyncJobJoinVO does not contain all the necessary information to populate a Job object.
|
||||
job.setId(uuid);
|
||||
job.setHref(basePath + JobsRouteHandler.BASE_ROUTE + "/" + uuid);
|
||||
job.setAutoCleared(Boolean.TRUE.toString());
|
||||
job.setExternal(Boolean.TRUE.toString());
|
||||
job.setLastUpdated(System.currentTimeMillis());
|
||||
job.setStartTime(startTime);
|
||||
job.setStatus(state);
|
||||
if ("complete".equalsIgnoreCase(state) || "finished".equalsIgnoreCase(state)) {
|
||||
job.setEndTime(System.currentTimeMillis());
|
||||
}
|
||||
job.setOwner(Ref.of(basePath + "/api/users/" + uuid, uuid));
|
||||
job.setActions(new Actions());
|
||||
job.setDescription("Something");
|
||||
job.setLink(Collections.emptyList());
|
||||
return job;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
// 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.converter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.cloudstack.veeam.VeeamControlService;
|
||||
import org.apache.cloudstack.veeam.api.VnicProfilesRouteHandler;
|
||||
import org.apache.cloudstack.veeam.api.dto.Ip;
|
||||
import org.apache.cloudstack.veeam.api.dto.Ips;
|
||||
import org.apache.cloudstack.veeam.api.dto.Mac;
|
||||
import org.apache.cloudstack.veeam.api.dto.Nic;
|
||||
import org.apache.cloudstack.veeam.api.dto.Ref;
|
||||
import org.apache.cloudstack.veeam.api.dto.ReportedDevice;
|
||||
import org.apache.cloudstack.veeam.api.dto.ReportedDevices;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.cloud.network.dao.NetworkVO;
|
||||
import com.cloud.vm.NicVO;
|
||||
|
||||
public class NicVOToNicConverter {
|
||||
|
||||
public static Nic toNic(final NicVO vo, final String vmUuid, final Function<Long, NetworkVO> networkResolver) {
|
||||
final String basePath = VeeamControlService.ContextPath.value();
|
||||
final Nic nic = new Nic();
|
||||
nic.setId(vo.getUuid());
|
||||
nic.setName(vo.getReserver());
|
||||
Mac mac = new Mac();
|
||||
mac.setAddress(vo.getMacAddress());
|
||||
nic.setMac(mac);
|
||||
nic.setLinked(true);
|
||||
nic.setPlugged(true);
|
||||
if (StringUtils.isBlank(vmUuid)) {
|
||||
nic.setVm(Ref.of(basePath + "/vms/" + vmUuid, vmUuid));
|
||||
nic.setHref(nic.getVm().href + "/nics/" + vo.getUuid());
|
||||
}
|
||||
nic.setInterfaceType("virtio");
|
||||
ReportedDevice device = getReportedDevice(vo, mac, nic.getVm());
|
||||
nic.setReportedDevices(new ReportedDevices(List.of(device)));
|
||||
if (networkResolver != null) {
|
||||
final NetworkVO network = networkResolver.apply(vo.getNetworkId());
|
||||
if (network != null) {
|
||||
nic.setVnicProfile(Ref.of(basePath + VnicProfilesRouteHandler.BASE_ROUTE + "/" + network.getUuid(), network.getUuid()));
|
||||
}
|
||||
}
|
||||
return nic;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static ReportedDevice getReportedDevice(NicVO vo, Mac mac, Ref vm) {
|
||||
ReportedDevice device = new ReportedDevice();
|
||||
device.setType("network");
|
||||
device.setId(vo.getUuid());
|
||||
device.setName("eth0");
|
||||
device.setMac(mac);
|
||||
Ip ip = new Ip();
|
||||
if (vo.getIPv4Address() != null) {
|
||||
ip.setAddress(vo.getIPv4Address());
|
||||
ip.setGateway(vo.getIPv4Gateway());
|
||||
ip.setVersion("v4");
|
||||
} else if (vo.getIPv6Address() != null) {
|
||||
ip.setAddress(vo.getIPv6Address());
|
||||
ip.setGateway(vo.getIPv6Gateway());
|
||||
ip.setVersion("v6");
|
||||
}
|
||||
device.setIps(new Ips(List.of(ip)));
|
||||
device.setVm(vm);
|
||||
return device;
|
||||
}
|
||||
|
||||
public static List<Nic> toNicList(final List<NicVO> vos, final String vmUuid, final Function<Long, NetworkVO> networkResolver) {
|
||||
return vos.stream()
|
||||
.map(vo -> toNic(vo, vmUuid, networkResolver))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
|
@ -25,14 +25,22 @@ import java.util.stream.Collectors;
|
|||
|
||||
import org.apache.cloudstack.veeam.VeeamControlService;
|
||||
import org.apache.cloudstack.veeam.api.ApiService;
|
||||
import org.apache.cloudstack.veeam.api.JobsRouteHandler;
|
||||
import org.apache.cloudstack.veeam.api.VmsRouteHandler;
|
||||
import org.apache.cloudstack.veeam.api.dto.Actions;
|
||||
import org.apache.cloudstack.veeam.api.dto.Bios;
|
||||
import org.apache.cloudstack.veeam.api.dto.Cpu;
|
||||
import org.apache.cloudstack.veeam.api.dto.DiskAttachment;
|
||||
import org.apache.cloudstack.veeam.api.dto.DiskAttachments;
|
||||
import org.apache.cloudstack.veeam.api.dto.EmptyElement;
|
||||
import org.apache.cloudstack.veeam.api.dto.Link;
|
||||
import org.apache.cloudstack.veeam.api.dto.Nic;
|
||||
import org.apache.cloudstack.veeam.api.dto.Nics;
|
||||
import org.apache.cloudstack.veeam.api.dto.Os;
|
||||
import org.apache.cloudstack.veeam.api.dto.Ref;
|
||||
import org.apache.cloudstack.veeam.api.dto.Topology;
|
||||
import org.apache.cloudstack.veeam.api.dto.Vm;
|
||||
import org.apache.cloudstack.veeam.api.dto.VmAction;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.cloud.api.query.vo.HostJoinVO;
|
||||
|
|
@ -49,7 +57,8 @@ public final class UserVmJoinVOToVmConverter {
|
|||
*
|
||||
* @param src UserVmJoinVO
|
||||
*/
|
||||
public static Vm toVm(final UserVmJoinVO src, final Function<Long, HostJoinVO> hostResolver) {
|
||||
public static Vm toVm(final UserVmJoinVO src, final Function<Long, HostJoinVO> hostResolver,
|
||||
final Function<Long, List<DiskAttachment>> disksResolver, final Function<UserVmJoinVO, List<Nic>> nicsResolver) {
|
||||
if (src == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -62,10 +71,13 @@ public final class UserVmJoinVOToVmConverter {
|
|||
dst.description = src.getDisplayName();
|
||||
dst.href = basePath + VmsRouteHandler.BASE_ROUTE + "/" + src.getUuid();
|
||||
dst.status = mapStatus(src.getState());
|
||||
final Date lastUpdated = src.getLastUpdated();
|
||||
final Date lastUpdated = src.getLastUpdated() != null ? src.getLastUpdated() : src.getCreated();
|
||||
if ("down".equals(dst.status)) {
|
||||
dst.stopTime = lastUpdated.getTime();
|
||||
}
|
||||
if ("up".equals(dst.status)) {
|
||||
dst.setStartTime(lastUpdated.getTime());
|
||||
}
|
||||
final Ref template = buildRef(
|
||||
basePath + ApiService.BASE_ROUTE,
|
||||
"templates",
|
||||
|
|
@ -93,24 +105,35 @@ public final class UserVmJoinVOToVmConverter {
|
|||
hostVo.getClusterUuid());
|
||||
}
|
||||
}
|
||||
Long hostId = src.getHostId() != null ? src.getHostId() : src.getLastHostId();
|
||||
if (hostId != null) {
|
||||
// I want to get Host data from hostJoinDao but this is a static method without dao access.
|
||||
|
||||
}
|
||||
|
||||
dst.memory = src.getRamSize() * 1024L * 1024L;
|
||||
|
||||
dst.cpu = new Cpu(src.getArch(), new Topology(src.getCpu(), src.getCpu(), 1));
|
||||
dst.cpu = new Cpu(src.getArch(), new Topology(src.getCpu(), 1, 1));
|
||||
dst.os = new Os();
|
||||
dst.os.type = src.getGuestOsId() % 2 == 0
|
||||
? "windows"
|
||||
: "linux";
|
||||
dst.bios = new Bios();
|
||||
dst.bios.type = "q35_secure_boot";
|
||||
dst.type = "server";
|
||||
dst.type = "desktop";
|
||||
dst.origin = "ovirt";
|
||||
dst.actions = null;dst.link = List.of(
|
||||
|
||||
if (disksResolver != null) {
|
||||
List<DiskAttachment> diskAttachments = disksResolver.apply(src.getId());
|
||||
dst.setDiskAttachments(new DiskAttachments(diskAttachments));
|
||||
}
|
||||
|
||||
if (disksResolver != null) {
|
||||
List<Nic> nics = nicsResolver.apply(src);
|
||||
dst.setNics(new Nics(nics));
|
||||
}
|
||||
|
||||
dst.actions = new Actions(List.of(
|
||||
new Link("start", dst.href + "/start"),
|
||||
new Link("stop", dst.href + "/stop"),
|
||||
new Link("shutdown", dst.href + "/shutdown")
|
||||
));
|
||||
dst.link = List.of(
|
||||
new Link("diskattachments",
|
||||
dst.href + "/diskattachments"),
|
||||
new Link("nics",
|
||||
|
|
@ -118,16 +141,26 @@ public final class UserVmJoinVOToVmConverter {
|
|||
new Link("snapshots",
|
||||
dst.href + "/snapshots")
|
||||
);
|
||||
dst.tags = new EmptyElement();
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
public static List<Vm> toVmList(final List<UserVmJoinVO> srcList, final Function<Long, HostJoinVO> hostResolver) {
|
||||
return srcList.stream()
|
||||
.map(v -> toVm(v, hostResolver))
|
||||
.map(v -> toVm(v, hostResolver, null, null))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static VmAction toVmAction(final UserVmJoinVO vm) {
|
||||
VmAction action = new VmAction();
|
||||
final String basePath = VeeamControlService.ContextPath.value();
|
||||
action.setVm(toVm(vm, null, null, null));
|
||||
action.setJob(Ref.of(basePath + JobsRouteHandler.BASE_ROUTE + vm.getUuid(), vm.getUuid()));
|
||||
action.setStatus("complete");
|
||||
return action;
|
||||
}
|
||||
|
||||
private static String mapStatus(final VirtualMachine.State state) {
|
||||
if (state == null) {
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import java.util.stream.Collectors;
|
|||
import org.apache.cloudstack.veeam.VeeamControlService;
|
||||
import org.apache.cloudstack.veeam.api.ApiService;
|
||||
import org.apache.cloudstack.veeam.api.DisksRouteHandler;
|
||||
import org.apache.cloudstack.veeam.api.VmsRouteHandler;
|
||||
import org.apache.cloudstack.veeam.api.dto.Actions;
|
||||
import org.apache.cloudstack.veeam.api.dto.Disk;
|
||||
import org.apache.cloudstack.veeam.api.dto.DiskAttachment;
|
||||
|
|
@ -132,24 +133,21 @@ public class VolumeJoinVOToDiskConverter {
|
|||
|
||||
public static DiskAttachment toDiskAttachment(final VolumeJoinVO vol) {
|
||||
final DiskAttachment da = new DiskAttachment();
|
||||
final String apiBase = VeeamControlService.ContextPath.value() + ApiService.BASE_ROUTE;
|
||||
final String basePath = VeeamControlService.ContextPath.value();
|
||||
final String apiBase = basePath + ApiService.BASE_ROUTE;
|
||||
|
||||
final String diskAttachmentId = vol.getUuid();
|
||||
final String diskAttachmentHref = apiBase + "/diskattachments/" + diskAttachmentId;
|
||||
|
||||
da.id = diskAttachmentId;
|
||||
da.href = diskAttachmentHref;
|
||||
|
||||
// Links
|
||||
da.disk = Ref.of(
|
||||
apiBase + "/disks/" + vol.getUuid(),
|
||||
vol.getUuid()
|
||||
);
|
||||
da.vm = Ref.of(
|
||||
apiBase + "/vms/" + vol.getVmUuid(),
|
||||
basePath + VmsRouteHandler.BASE_ROUTE + "/" + vol.getVmUuid(),
|
||||
vol.getVmUuid()
|
||||
);
|
||||
|
||||
da.id = diskAttachmentId;
|
||||
da.href = da.vm.href + "/diskattachements/" + diskAttachmentId;;
|
||||
|
||||
// Links
|
||||
da.disk = toDisk(vol);
|
||||
|
||||
// Properties
|
||||
da.active = "true";
|
||||
da.bootable = "false";
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ public final class DiskAttachment {
|
|||
@JsonProperty("uses_scsi_reservation")
|
||||
public String usesScsiReservation;
|
||||
|
||||
public Ref disk;
|
||||
public Disk disk;
|
||||
public Ref vm;
|
||||
|
||||
public String href;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
// 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.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class Ip {
|
||||
|
||||
private String address;
|
||||
private String gateway;
|
||||
private String netmask;
|
||||
private String version;
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public String getGateway() {
|
||||
return gateway;
|
||||
}
|
||||
|
||||
public void setGateway(String gateway) {
|
||||
this.gateway = gateway;
|
||||
}
|
||||
|
||||
public String getNetmask() {
|
||||
return netmask;
|
||||
}
|
||||
|
||||
public void setNetmask(String netmask) {
|
||||
this.netmask = netmask;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
|
|
@ -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.veeam.api.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class Ips {
|
||||
|
||||
@JacksonXmlElementWrapper(useWrapping = false)
|
||||
private List<Ip> ip;
|
||||
|
||||
public Ips(final List<Ip> ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public List<Ip> getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(List<Ip> ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
}
|
||||
|
|
@ -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.veeam.api.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class Job {
|
||||
private String autoCleared;
|
||||
private String external;
|
||||
private Long lastUpdated;
|
||||
private Long startTime;
|
||||
private Long endTime;
|
||||
private String status;
|
||||
private Ref owner;
|
||||
private Actions actions;
|
||||
private String description;
|
||||
private List<Link> link;
|
||||
private String href;
|
||||
private String id;
|
||||
|
||||
// getters and setters
|
||||
public String getAutoCleared() { return autoCleared; }
|
||||
public void setAutoCleared(String autoCleared) { this.autoCleared = autoCleared; }
|
||||
|
||||
public String getExternal() { return external; }
|
||||
public void setExternal(String external) { this.external = external; }
|
||||
|
||||
public Long getLastUpdated() { return lastUpdated; }
|
||||
public void setLastUpdated(Long lastUpdated) { this.lastUpdated = lastUpdated; }
|
||||
|
||||
public Long getStartTime() { return startTime; }
|
||||
public void setStartTime(Long startTime) { this.startTime = startTime; }
|
||||
|
||||
public Long getEndTime() { return endTime; }
|
||||
public void setEndTime(Long endTime) { this.endTime = endTime; }
|
||||
|
||||
public String getStatus() { return status; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
|
||||
public Ref getOwner() { return owner; }
|
||||
public void setOwner(Ref owner) { this.owner = owner; }
|
||||
|
||||
public Actions getActions() { return actions; }
|
||||
public void setActions(Actions actions) { this.actions = actions; }
|
||||
|
||||
public String getDescription() { return description; }
|
||||
public void setDescription(String description) { this.description = description; }
|
||||
|
||||
public List<Link> getLink() { return link; }
|
||||
public void setLink(List<Link> link) { this.link = link; }
|
||||
|
||||
public String getHref() { return href; }
|
||||
public void setHref(String href) { this.href = href; }
|
||||
|
||||
public String getId() { return id; }
|
||||
public void setId(String id) { this.id = id; }
|
||||
}
|
||||
|
|
@ -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 ownershjob. 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.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class Jobs {
|
||||
|
||||
@JacksonXmlElementWrapper(useWrapping = false)
|
||||
private List<Job> job;
|
||||
|
||||
public Jobs(final List<Job> job) {
|
||||
this.job = job;
|
||||
}
|
||||
|
||||
public List<Job> getJob() {
|
||||
return job;
|
||||
}
|
||||
|
||||
public void setJob(List<Job> job) {
|
||||
this.job = job;
|
||||
}
|
||||
}
|
||||
|
|
@ -15,20 +15,20 @@
|
|||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.veeam.api.response;
|
||||
package org.apache.cloudstack.veeam.api.dto;
|
||||
|
||||
import org.apache.cloudstack.veeam.api.dto.Vm;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
/**
|
||||
* Required entity response:
|
||||
* { "vm": { .. } }
|
||||
*/
|
||||
public final class VmEntityResponse {
|
||||
public Vm vm;
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class Mac {
|
||||
|
||||
public VmEntityResponse() {}
|
||||
private String address;
|
||||
|
||||
public VmEntityResponse(final Vm vm) {
|
||||
this.vm = vm;
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
}
|
||||
|
|
@ -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.veeam.api.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class Nic {
|
||||
|
||||
private String href;
|
||||
private String id;
|
||||
private String name;
|
||||
private String description;
|
||||
@JacksonXmlProperty(localName = "interface")
|
||||
@JsonProperty("interface")
|
||||
private String interfaceType;
|
||||
private String linked;
|
||||
private Mac mac;
|
||||
private String plugged;
|
||||
private Ref vnicProfile;
|
||||
private Ref vm;
|
||||
private ReportedDevices reportedDevices;
|
||||
|
||||
public Nic() {
|
||||
}
|
||||
|
||||
public String getHref() {
|
||||
return href;
|
||||
}
|
||||
|
||||
public void setHref(final String href) {
|
||||
this.href = href;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(final String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getInterfaceType() {
|
||||
return interfaceType;
|
||||
}
|
||||
|
||||
public void setInterfaceType(String interfaceType) {
|
||||
this.interfaceType = interfaceType;
|
||||
}
|
||||
|
||||
public boolean isLinked() {
|
||||
return Boolean.parseBoolean(linked);
|
||||
}
|
||||
|
||||
public void setLinked(boolean linked) {
|
||||
this.linked = Boolean.toString(linked);
|
||||
}
|
||||
|
||||
public Mac getMac() {
|
||||
return mac;
|
||||
}
|
||||
|
||||
public void setMac(Mac mac) {
|
||||
this.mac = mac;
|
||||
}
|
||||
|
||||
public boolean isPlugged() {
|
||||
return Boolean.parseBoolean(plugged);
|
||||
}
|
||||
|
||||
public void setPlugged(boolean plugged) {
|
||||
this.plugged = Boolean.toString(plugged);
|
||||
}
|
||||
|
||||
public Ref getVnicProfile() {
|
||||
return vnicProfile;
|
||||
}
|
||||
|
||||
public void setVnicProfile(Ref vnicProfile) {
|
||||
this.vnicProfile = vnicProfile;
|
||||
}
|
||||
|
||||
public Ref getVm() {
|
||||
return vm;
|
||||
}
|
||||
|
||||
public void setVm(Ref vm) {
|
||||
this.vm = vm;
|
||||
}
|
||||
|
||||
public ReportedDevices getReportedDevices() {
|
||||
return reportedDevices;
|
||||
}
|
||||
|
||||
public void setReportedDevices(ReportedDevices reportedDevices) {
|
||||
this.reportedDevices = reportedDevices;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
// 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.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JacksonXmlRootElement(localName = "nics")
|
||||
public final class Nics {
|
||||
|
||||
@JsonProperty("nic")
|
||||
@JacksonXmlElementWrapper(useWrapping = false)
|
||||
public List<Nic> nic;
|
||||
|
||||
public Nics() {}
|
||||
|
||||
public Nics(final List<Nic> nic) {
|
||||
this.nic = nic;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
// 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.dto;
|
||||
|
||||
public class ReportedDevice {
|
||||
private String comment;
|
||||
private String description;
|
||||
private Ips ips;
|
||||
private String id;
|
||||
private Mac Mac;
|
||||
private String name;
|
||||
private String type;
|
||||
private Ref vm;
|
||||
|
||||
public String getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
public void setComment(String comment) {
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Ips getIps() {
|
||||
return ips;
|
||||
}
|
||||
|
||||
public void setIps(Ips ips) {
|
||||
this.ips = ips;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Mac getMac() {
|
||||
return Mac;
|
||||
}
|
||||
|
||||
public void setMac(Mac mac) {
|
||||
Mac = mac;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Ref getVm() {
|
||||
return vm;
|
||||
}
|
||||
|
||||
public void setVm(Ref vm) {
|
||||
this.vm = vm;
|
||||
}
|
||||
}
|
||||
|
|
@ -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.veeam.api.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class ReportedDevices {
|
||||
|
||||
@JacksonXmlElementWrapper(useWrapping = false)
|
||||
private List<ReportedDevice> reportedDevice;
|
||||
|
||||
public ReportedDevices(final List<ReportedDevice> reportedDevice) {
|
||||
this.reportedDevice = reportedDevice;
|
||||
}
|
||||
|
||||
public List<ReportedDevice> getReportedDevice() {
|
||||
return reportedDevice;
|
||||
}
|
||||
|
||||
public void setReportedDevice(List<ReportedDevice> reportedDevice) {
|
||||
this.reportedDevice = reportedDevice;
|
||||
}
|
||||
}
|
||||
|
|
@ -46,6 +46,7 @@ public final class Vm {
|
|||
@JsonProperty("stop_time")
|
||||
@JacksonXmlProperty(localName = "stop_time")
|
||||
public Long stopTime; // epoch millis
|
||||
private Long startTime; // epoch millis
|
||||
|
||||
public Ref template;
|
||||
|
||||
|
|
@ -68,6 +69,43 @@ public final class Vm {
|
|||
public Actions actions; // actions.link[]
|
||||
@JacksonXmlElementWrapper(useWrapping = false)
|
||||
public List<Link> link; // related resources
|
||||
public EmptyElement tags; // empty <tags/>
|
||||
private DiskAttachments diskAttachments;
|
||||
private Nics nics;
|
||||
|
||||
private VmInitialization initialization;
|
||||
|
||||
public Vm() {}
|
||||
|
||||
public Long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public void setStartTime(Long startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public DiskAttachments getDiskAttachments() {
|
||||
return diskAttachments;
|
||||
}
|
||||
|
||||
public void setDiskAttachments(DiskAttachments diskAttachments) {
|
||||
this.diskAttachments = diskAttachments;
|
||||
}
|
||||
|
||||
public Nics getNics() {
|
||||
return nics;
|
||||
}
|
||||
|
||||
public void setNics(Nics nics) {
|
||||
this.nics = nics;
|
||||
}
|
||||
|
||||
public VmInitialization getInitialization() {
|
||||
return initialization;
|
||||
}
|
||||
|
||||
public void setInitialization(VmInitialization initialization) {
|
||||
this.initialization = initialization;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
// 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.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class VmAction {
|
||||
private Ref job;
|
||||
private Vm vm;
|
||||
private String status;
|
||||
|
||||
public Ref getJob() {
|
||||
return job;
|
||||
}
|
||||
|
||||
public void setJob(Ref job) {
|
||||
this.job = job;
|
||||
}
|
||||
|
||||
public Vm getVm() {
|
||||
return vm;
|
||||
}
|
||||
|
||||
public void setVm(Vm vm) {
|
||||
this.vm = vm;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// 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.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class VmInitialization {
|
||||
|
||||
private String contentData;
|
||||
|
||||
public String getContentData() {
|
||||
return contentData;
|
||||
}
|
||||
|
||||
public void setContentData(String contentData) {
|
||||
this.contentData = contentData;
|
||||
}
|
||||
}
|
||||
|
|
@ -15,12 +15,10 @@
|
|||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.veeam.api.response;
|
||||
package org.apache.cloudstack.veeam.api.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.veeam.api.dto.Vm;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
|
|
@ -34,14 +32,14 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
|||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonPropertyOrder({ "vm" })
|
||||
@JacksonXmlRootElement(localName = "vms")
|
||||
public final class VmCollectionResponse {
|
||||
public final class Vms {
|
||||
@JsonProperty("vm")
|
||||
@JacksonXmlElementWrapper(useWrapping = false)
|
||||
public List<Vm> vm;
|
||||
|
||||
public VmCollectionResponse() {}
|
||||
public Vms() {}
|
||||
|
||||
public VmCollectionResponse(final List<Vm> vm) {
|
||||
public Vms(final List<Vm> vm) {
|
||||
this.vm = vm;
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ package org.apache.cloudstack.veeam.utils;
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||
|
|
@ -38,6 +39,7 @@ public class Mapper {
|
|||
private static void configure(final ObjectMapper mapper) {
|
||||
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
|
||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
// If you ever add enums etc:
|
||||
// mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
|
||||
// mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
|
||||
|
|
|
|||
|
|
@ -42,11 +42,12 @@
|
|||
<bean id="vmsRouteHandler" class="org.apache.cloudstack.veeam.api.VmsRouteHandler"/>
|
||||
<bean id="disksRouteHandler" class="org.apache.cloudstack.veeam.api.DisksRouteHandler"/>
|
||||
<bean id="imageTransfersRouteHandler" class="org.apache.cloudstack.veeam.api.ImageTransfersRouteHandler"/>
|
||||
<bean id="jobsRouteHandler" class="org.apache.cloudstack.veeam.api.JobsRouteHandler"/>
|
||||
|
||||
<bean id="veeamControlService" class="org.apache.cloudstack.veeam.VeeamControlServiceImpl" >
|
||||
<property name="routeHandlers" value="#{routeHandlerRegistry.registered}" />
|
||||
</bean>
|
||||
|
||||
<bean id="userResourceAdapter" class="org.apache.cloudstack.veeam.adapter.UserResourceAdapter"/>
|
||||
<bean id="serverAdapter" class="org.apache.cloudstack.veeam.adapter.ServerAdapter"/>
|
||||
|
||||
</beans>
|
||||
|
|
|
|||
|
|
@ -204,5 +204,5 @@ public interface UserVmManager extends UserVmService {
|
|||
*/
|
||||
boolean isVMPartOfAnyCKSCluster(VMInstanceVO vm);
|
||||
|
||||
boolean isDummyTemplate(HypervisorType hypervisorType, Long templateId);
|
||||
boolean isBlankInstanceTemplate(VirtualMachineTemplate template);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -423,7 +423,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
|
||||
private static final long GiB_TO_BYTES = 1024 * 1024 * 1024;
|
||||
|
||||
public static final String KVM_VM_DUMMY_TEMPLATE_NAME = "kvm-vm-dummy-template";
|
||||
private static final String KVM_VM_DUMMY_TEMPLATE_NAME = "kvm-vm-dummy-template";
|
||||
|
||||
|
||||
@Inject
|
||||
|
|
@ -658,7 +658,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
private boolean _instanceNameFlag;
|
||||
private int _scaleRetry;
|
||||
private Map<Long, VmAndCountDetails> vmIdCountMap = new ConcurrentHashMap<>();
|
||||
private static VMTemplateVO KVM_VM_DUMMY_TEMPLATE;
|
||||
|
||||
protected static long ROOT_DEVICE_ID = 0;
|
||||
|
||||
|
|
@ -2505,17 +2504,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
_scaleRetry = NumbersUtil.parseInt(configs.get(Config.ScaleRetry.key()), 2);
|
||||
|
||||
_vmIpFetchThreadExecutor = Executors.newFixedThreadPool(VmIpFetchThreadPoolMax.value(), new NamedThreadFactory("vmIpFetchThread"));
|
||||
|
||||
KVM_VM_DUMMY_TEMPLATE = _templateDao.findByAccountAndName(Account.ACCOUNT_ID_SYSTEM, KVM_VM_DUMMY_TEMPLATE_NAME);
|
||||
if (KVM_VM_DUMMY_TEMPLATE == null) {
|
||||
KVM_VM_DUMMY_TEMPLATE = VMTemplateVO.createSystemIso(_templateDao.getNextInSequence(Long.class, "id"), KVM_VM_DUMMY_TEMPLATE_NAME, KVM_VM_DUMMY_TEMPLATE_NAME, true,
|
||||
"", true, 64, Account.ACCOUNT_ID_SYSTEM, "",
|
||||
"Dummy Template for KVM VM", false, 1);
|
||||
KVM_VM_DUMMY_TEMPLATE.setState(VirtualMachineTemplate.State.Active);
|
||||
KVM_VM_DUMMY_TEMPLATE.setFormat(ImageFormat.QCOW2);
|
||||
KVM_VM_DUMMY_TEMPLATE = _templateDao.persist(KVM_VM_DUMMY_TEMPLATE);
|
||||
}
|
||||
|
||||
logger.info("User VM Manager is configured.");
|
||||
|
||||
return true;
|
||||
|
|
@ -3945,7 +3933,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
_accountMgr.checkAccess(owner, _diskOfferingDao.findById(diskOfferingId), zone);
|
||||
|
||||
// If no network is specified, find system security group enabled network
|
||||
if (isDummyTemplate(hypervisor, template.getId())) {
|
||||
if (isBlankInstanceTemplate(template)) {
|
||||
logger.debug("Template is a dummy template for hypervisor {}, skipping network allocation in an advanced security group enabled zone", hypervisor);
|
||||
} else if (networkIdList == null || networkIdList.isEmpty()) {
|
||||
Network networkWithSecurityGroup = _networkModel.getNetworkWithSGWithFreeIPs(owner, zone.getId());
|
||||
|
|
@ -4060,7 +4048,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
_accountMgr.checkAccess(owner, diskOffering, zone);
|
||||
|
||||
List<HypervisorType> vpcSupportedHTypes = _vpcMgr.getSupportedVpcHypervisors();
|
||||
if (isDummyTemplate(hypervisor, template.getId())) {
|
||||
if (isBlankInstanceTemplate(template)) {
|
||||
logger.debug("Template is a dummy template for hypervisor {}, skipping network allocation in an advanced zone", hypervisor);
|
||||
} else if (networkIdList == null || networkIdList.isEmpty()) {
|
||||
NetworkVO defaultNetwork = getDefaultNetwork(zone, owner, false);
|
||||
|
|
@ -4497,7 +4485,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
}
|
||||
}
|
||||
|
||||
if (TemplateType.SYSTEM.equals(template.getTemplateType()) && !CKS_NODE.equals(vmType) && !SHAREDFSVM.equals(vmType) && !isDummyTemplate(hypervisorType, template.getId())) {
|
||||
if (TemplateType.SYSTEM.equals(template.getTemplateType()) && !CKS_NODE.equals(vmType) && !SHAREDFSVM.equals(vmType) && !isBlankInstanceTemplate(template)) {
|
||||
throw new InvalidParameterValueException(String.format("Unable to use system template %s to deploy a user vm", template));
|
||||
}
|
||||
|
||||
|
|
@ -4510,7 +4498,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
if (CollectionUtils.isEmpty(snapshotsOnZone)) {
|
||||
throw new InvalidParameterValueException("The snapshot does not exist on zone " + zone.getId());
|
||||
}
|
||||
} else if (!isDummyTemplate(hypervisorType, template.getId())) {
|
||||
} else if (!isBlankInstanceTemplate(template)) {
|
||||
List<VMTemplateZoneVO> listZoneTemplate = _templateZoneDao.listByZoneTemplate(zone.getId(), template.getId());
|
||||
if (listZoneTemplate == null || listZoneTemplate.isEmpty()) {
|
||||
throw new InvalidParameterValueException("The template " + template.getId() + " is not available for use");
|
||||
|
|
@ -4625,7 +4613,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
// by Agent Manager in order to configure default
|
||||
// gateway for the vm
|
||||
if (defaultNetworkNumber == 0) {
|
||||
if (isDummyTemplate(hypervisorType, template.getId())) {
|
||||
if (isBlankInstanceTemplate(template)) {
|
||||
logger.debug("Template is a dummy template for hypervisor {}, vm can be created without a default network", hypervisorType);
|
||||
} else {
|
||||
throw new InvalidParameterValueException("At least 1 default network has to be specified for the vm");
|
||||
|
|
@ -4791,7 +4779,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
return rootDiskSize;
|
||||
} else {
|
||||
// For baremetal, size can be 0 (zero)
|
||||
Long templateSize = _templateDao.findById(template.getId()).getSize();
|
||||
Long templateSize = template.getSize();
|
||||
if (templateSize != null) {
|
||||
return templateSize;
|
||||
}
|
||||
|
|
@ -5347,7 +5335,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
@ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", async = true)
|
||||
public UserVm startVirtualMachine(DeployVMCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException, ConcurrentOperationException, ResourceAllocationException {
|
||||
long vmId = cmd.getEntityId();
|
||||
if (!cmd.getStartVm() || cmd.getDummy()) {
|
||||
if (!cmd.getStartVm() || cmd.isBlankInstance()) {
|
||||
return getUserVm(vmId);
|
||||
}
|
||||
Long podId = null;
|
||||
|
|
@ -6495,10 +6483,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
(!(HypervisorType.KVM.equals(template.getHypervisorType()) || HypervisorType.KVM.equals(cmd.getHypervisor())))) {
|
||||
throw new InvalidParameterValueException("Deploying a virtual machine with existing volume/snapshot is supported only from KVM hypervisors");
|
||||
}
|
||||
if (template == null && HypervisorType.KVM.equals(cmd.getHypervisor()) && cmd.getDummy()) {
|
||||
template = KVM_VM_DUMMY_TEMPLATE;
|
||||
if (template == null && HypervisorType.KVM.equals(cmd.getHypervisor()) && cmd.isBlankInstance()) {
|
||||
template = getBlankInstanceTemplate();
|
||||
logger.info("Creating launch permission for Dummy template");
|
||||
LaunchPermissionVO launchPermission = new LaunchPermissionVO(KVM_VM_DUMMY_TEMPLATE.getId(), owner.getId());
|
||||
LaunchPermissionVO launchPermission = new LaunchPermissionVO(template.getId(), owner.getId());
|
||||
launchPermissionDao.persist(launchPermission);
|
||||
}
|
||||
// Make sure a valid template ID was specified
|
||||
|
|
@ -6660,9 +6648,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
applyLeaseOnCreateInstance(vm, cmd.getLeaseDuration(), cmd.getLeaseExpiryAction(), svcOffering);
|
||||
}
|
||||
|
||||
if (KVM_VM_DUMMY_TEMPLATE != null && template.getId() == KVM_VM_DUMMY_TEMPLATE.getId() && cmd instanceof DeployVMCmd && ((DeployVMCmd) cmd).getDummy()) {
|
||||
if (isBlankInstanceTemplate(template) && cmd instanceof DeployVMCmd && ((DeployVMCmd) cmd).isBlankInstance()) {
|
||||
logger.info("Revoking launch permission for Dummy template");
|
||||
launchPermissionDao.removePermissions(KVM_VM_DUMMY_TEMPLATE.getId(), Collections.singletonList(owner.getId()));
|
||||
launchPermissionDao.removePermissions(template.getId(), Collections.singletonList(owner.getId()));
|
||||
}
|
||||
|
||||
return vm;
|
||||
|
|
@ -10101,10 +10089,23 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isDummyTemplate(HypervisorType hypervisorType, Long templateId) {
|
||||
if (HypervisorType.KVM.equals(hypervisorType) && KVM_VM_DUMMY_TEMPLATE != null && KVM_VM_DUMMY_TEMPLATE.getId() == templateId) {
|
||||
return true;
|
||||
public boolean isBlankInstanceTemplate(VirtualMachineTemplate template) {
|
||||
return KVM_VM_DUMMY_TEMPLATE_NAME.equals(template.getUniqueName());
|
||||
}
|
||||
|
||||
VMTemplateVO getBlankInstanceTemplate() {
|
||||
VMTemplateVO template = _templateDao.findByName(KVM_VM_DUMMY_TEMPLATE_NAME);
|
||||
if (template != null) {
|
||||
return template;
|
||||
}
|
||||
return false;
|
||||
template = VMTemplateVO.createSystemIso(_templateDao.getNextInSequence(Long.class, "id"),
|
||||
KVM_VM_DUMMY_TEMPLATE_NAME, KVM_VM_DUMMY_TEMPLATE_NAME, true,
|
||||
"", true, 64, Account.ACCOUNT_ID_SYSTEM, "",
|
||||
"Dummy Template for KVM VM", false, 1);
|
||||
template.setState(VirtualMachineTemplate.State.Active);
|
||||
template.setFormat(ImageFormat.QCOW2);
|
||||
template = _templateDao.persist(template);
|
||||
// _templateDao.remove(template.getId());
|
||||
return template;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -478,6 +478,16 @@ public class IncrementalBackupServiceImpl extends ManagerBase implements Increme
|
|||
return imageTransferDao.findById(imageTransfer.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancelImageTransfer(long imageTransferId) {
|
||||
ImageTransferVO imageTransfer = imageTransferDao.findById(imageTransferId);
|
||||
if (imageTransfer == null) {
|
||||
throw new CloudRuntimeException("Image transfer not found: " + imageTransferId);
|
||||
}
|
||||
// ToDo: Implement cancel logic
|
||||
return true;
|
||||
}
|
||||
|
||||
private void finalizeDownloadImageTransfer(ImageTransferVO imageTransfer) {
|
||||
|
||||
String transferId = imageTransfer.getUuid();
|
||||
|
|
@ -552,8 +562,11 @@ public class IncrementalBackupServiceImpl extends ManagerBase implements Increme
|
|||
|
||||
@Override
|
||||
public boolean finalizeImageTransfer(FinalizeImageTransferCmd cmd) {
|
||||
Long imageTransferId = cmd.getImageTransferId();
|
||||
return finalizeImageTransfer(cmd.getImageTransferId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean finalizeImageTransfer(final long imageTransferId) {
|
||||
ImageTransferVO imageTransfer = imageTransferDao.findById(imageTransferId);
|
||||
if (imageTransfer == null) {
|
||||
throw new CloudRuntimeException("Image transfer not found: " + imageTransferId);
|
||||
|
|
@ -566,6 +579,8 @@ public class IncrementalBackupServiceImpl extends ManagerBase implements Increme
|
|||
}
|
||||
imageTransfer.setPhase(ImageTransferVO.Phase.finished);
|
||||
imageTransferDao.update(imageTransfer.getId(), imageTransfer);
|
||||
// ToDo: check this
|
||||
// imageTransferDao.remove(imageTransfer.getId());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -656,7 +671,8 @@ public class IncrementalBackupServiceImpl extends ManagerBase implements Increme
|
|||
response.setBackupId(backup.getUuid());
|
||||
}
|
||||
Long volumeId = imageTransferVO.getDiskId();
|
||||
Volume volume = volumeDao.findById(volumeId);
|
||||
// ToDo: fix volume deletion leaving orphan image transfer record
|
||||
Volume volume = volumeDao.findByIdIncludingRemoved(volumeId);
|
||||
response.setDiskId(volume.getUuid());
|
||||
response.setTransferUrl(imageTransferVO.getTransferUrl());
|
||||
response.setPhase(imageTransferVO.getPhase().toString());
|
||||
|
|
|
|||
Loading…
Reference in New Issue