mirror of
https://github.com/apache/cloudstack.git
synced 2025-11-03 04:12:31 +01:00
refactoring createVolume to new API framework
This commit is contained in:
parent
b73cd10fbe
commit
1e46e2e588
@ -18,40 +18,20 @@
|
||||
|
||||
package com.cloud.api.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.api.BaseCmd;
|
||||
import com.cloud.api.BaseAsyncCreateCmd;
|
||||
import com.cloud.api.BaseCmd.Manager;
|
||||
import com.cloud.api.Implementation;
|
||||
import com.cloud.api.Parameter;
|
||||
import com.cloud.api.ServerApiException;
|
||||
import com.cloud.async.executor.VolumeOperationResultObject;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.api.response.VolumeResponse;
|
||||
import com.cloud.serializer.SerializerHelper;
|
||||
import com.cloud.storage.DiskOfferingVO;
|
||||
import com.cloud.storage.Snapshot;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
|
||||
public class CreateVolumeCmd extends BaseCmd {
|
||||
@Implementation(createMethod="createVolumeDB", method="createVolume", manager=Manager.StorageManager)
|
||||
public class CreateVolumeCmd extends BaseAsyncCreateCmd {
|
||||
public static final Logger s_logger = Logger.getLogger(CreateVolumeCmd.class.getName());
|
||||
private static final String s_name = "createvolumeresponse";
|
||||
private static final List<Pair<Enum, Boolean>> s_properties = new ArrayList<Pair<Enum, Boolean>>();
|
||||
|
||||
static {
|
||||
s_properties.add(new Pair<Enum, Boolean>(BaseCmd.Properties.ACCOUNT_OBJ, Boolean.FALSE));
|
||||
s_properties.add(new Pair<Enum, Boolean>(BaseCmd.Properties.USER_ID, Boolean.FALSE));
|
||||
|
||||
s_properties.add(new Pair<Enum, Boolean>(BaseCmd.Properties.ACCOUNT, Boolean.FALSE));
|
||||
s_properties.add(new Pair<Enum, Boolean>(BaseCmd.Properties.DISK_OFFERING_ID, Boolean.FALSE));
|
||||
s_properties.add(new Pair<Enum, Boolean>(BaseCmd.Properties.DOMAIN_ID, Boolean.FALSE));
|
||||
s_properties.add(new Pair<Enum, Boolean>(BaseCmd.Properties.NAME, Boolean.TRUE));
|
||||
s_properties.add(new Pair<Enum, Boolean>(BaseCmd.Properties.SNAPSHOT_ID, Boolean.FALSE));
|
||||
s_properties.add(new Pair<Enum, Boolean>(BaseCmd.Properties.ZONE_ID, Boolean.FALSE));
|
||||
s_properties.add(new Pair<Enum, Boolean>(BaseCmd.Properties.SIZE, Boolean.FALSE));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
@ -69,6 +49,9 @@ public class CreateVolumeCmd extends BaseCmd {
|
||||
@Parameter(name="name", type=CommandType.STRING, required=true)
|
||||
private String volumeName;
|
||||
|
||||
@Parameter(name="size", type=CommandType.LONG)
|
||||
private Long size;
|
||||
|
||||
@Parameter(name="snapshotid", type=CommandType.LONG)
|
||||
private Long snapshotId;
|
||||
|
||||
@ -96,6 +79,10 @@ public class CreateVolumeCmd extends BaseCmd {
|
||||
return volumeName;
|
||||
}
|
||||
|
||||
public Long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public Long getSnapshotId() {
|
||||
return snapshotId;
|
||||
}
|
||||
@ -120,145 +107,30 @@ public class CreateVolumeCmd extends BaseCmd {
|
||||
|
||||
@Override
|
||||
public String getResponse() {
|
||||
}
|
||||
VolumeVO volume = (VolumeVO)getResponseObject();
|
||||
|
||||
@Override
|
||||
public List<Pair<String, Object>> execute(Map<String, Object> params) {
|
||||
Account account = (Account) params.get(BaseCmd.Properties.ACCOUNT_OBJ.getName());
|
||||
Long userId = (Long) params.get(BaseCmd.Properties.USER_ID.getName());
|
||||
String accountName = (String) params.get(BaseCmd.Properties.ACCOUNT.getName());
|
||||
Long domainId = (Long) params.get(BaseCmd.Properties.DOMAIN_ID.getName());
|
||||
String name = (String) params.get(BaseCmd.Properties.NAME.getName());
|
||||
Long zoneId = (Long) params.get(BaseCmd.Properties.ZONE_ID.getName());
|
||||
Long diskOfferingId = (Long) params.get(BaseCmd.Properties.DISK_OFFERING_ID.getName());
|
||||
Long snapshotId = (Long)params.get(BaseCmd.Properties.SNAPSHOT_ID.getName());
|
||||
Long size = (Long)params.get(BaseCmd.Properties.SIZE.getName());
|
||||
|
||||
if (account == null) {
|
||||
// Admin API call
|
||||
|
||||
// Check if accountName was passed in
|
||||
if ((accountName == null) || (domainId == null)) {
|
||||
throw new ServerApiException(BaseCmd.PARAM_ERROR, "Account and domainId must be passed in.");
|
||||
}
|
||||
|
||||
// Look up the account by name and domain ID
|
||||
account = getManagementServer().findActiveAccount(accountName, domainId);
|
||||
|
||||
// If the account is null, this means that the accountName and domainId passed in were invalid
|
||||
if (account == null)
|
||||
throw new ServerApiException(BaseCmd.PARAM_ERROR, "Unable to find account with name: " + accountName + " and domain ID: " + domainId);
|
||||
} else {
|
||||
// User API call
|
||||
|
||||
// If the account is an admin, and accountName/domainId were passed in, use the account specified by these parameters
|
||||
if (isAdmin(account.getType())) {
|
||||
if (domainId != null) {
|
||||
if (!getManagementServer().isChildDomain(account.getDomainId(), domainId)) {
|
||||
throw new ServerApiException(BaseCmd.ACCOUNT_ERROR, "Unable to create volume in domain " + domainId + ", permission denied.");
|
||||
}
|
||||
if (accountName != null) {
|
||||
account = getManagementServer().findActiveAccount(accountName, domainId);
|
||||
|
||||
if (account == null)
|
||||
throw new ServerApiException(BaseCmd.PARAM_ERROR, "Unable to find account with name: " + accountName + " and domain ID: " + domainId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If command is executed via the Admin API, set userId to the id of System account (1)
|
||||
if (userId == null) {
|
||||
userId = Long.valueOf(Account.ACCOUNT_ID_SYSTEM);
|
||||
}
|
||||
|
||||
if(size==null){
|
||||
size = Long.valueOf(0);
|
||||
}
|
||||
VolumeResponse response = new VolumeResponse();
|
||||
response.setId(volume.getId());
|
||||
response.setName(param.getName());
|
||||
response.setVolumeType(volume.getVolumeType().toString());
|
||||
response.setSize(volume.getSize());
|
||||
response.setCreated(volume.getCreated());
|
||||
response.setState(volume.getStatus().toString());
|
||||
response.setAccountName(ggetManagementServer().findAccountById(volume.getAccountId()).getAccountName());
|
||||
response.setDomainId(volume.getDomainId());
|
||||
response.setDiskOfferingId(volume.getDiskOfferingId());
|
||||
|
||||
boolean useSnapshot = false;
|
||||
if (snapshotId == null) {
|
||||
if ((zoneId == null)) {
|
||||
throw new ServerApiException(BaseCmd.PARAM_ERROR, "Missing parameter,zoneid must be specified.");
|
||||
}
|
||||
|
||||
if (diskOfferingId == null && size == 0) {
|
||||
throw new ServerApiException(BaseCmd.PARAM_ERROR, "Missing parameter(s),either a positive volume size or a valid disk offering id must be specified.");
|
||||
} else if(diskOfferingId == null && size != 0) {
|
||||
//validate the size to ensure between min and max size range
|
||||
try {
|
||||
boolean ok = getManagementServer().validateCustomVolumeSizeRange(size);
|
||||
|
||||
if (!ok) {
|
||||
throw new ServerApiException(BaseCmd.PARAM_ERROR, "Invalid size for custom volume creation:");
|
||||
}
|
||||
} catch (InvalidParameterValueException e) {
|
||||
s_logger.warn("Invalid size for custom volume creation");
|
||||
throw new ServerApiException(BaseCmd.PARAM_ERROR, "Invalid size for custom volume creation:"+e.getMessage());
|
||||
}
|
||||
|
||||
//this is the case of creating var size vol with private disk offering
|
||||
List<DiskOfferingVO> privateTemplateList = getManagementServer().findPrivateDiskOffering();
|
||||
diskOfferingId = privateTemplateList.get(0).getId(); //we use this id for creating volume
|
||||
}
|
||||
} else {
|
||||
useSnapshot = true;
|
||||
//Verify parameters
|
||||
Snapshot snapshotCheck = getManagementServer().findSnapshotById(snapshotId);
|
||||
if (snapshotCheck == null) {
|
||||
throw new ServerApiException (BaseCmd.SNAPSHOT_INVALID_PARAM_ERROR, "unable to find a snapshot with id " + snapshotId);
|
||||
}
|
||||
|
||||
if (account != null) {
|
||||
if (isAdmin(account.getType())) {
|
||||
Account snapshotOwner = getManagementServer().findAccountById(snapshotCheck.getAccountId());
|
||||
if (!getManagementServer().isChildDomain(account.getDomainId(), snapshotOwner.getDomainId())) {
|
||||
throw new ServerApiException(BaseCmd.ACCOUNT_ERROR, "Unable to create volume from snapshot with id " + snapshotId + ", permission denied.");
|
||||
}
|
||||
} else if (account.getId().longValue() != snapshotCheck.getAccountId()) {
|
||||
throw new ServerApiException(BaseCmd.SNAPSHOT_INVALID_PARAM_ERROR, "unable to find a snapshot with id " + snapshotId + " for this account");
|
||||
}
|
||||
}
|
||||
if (volume.getDiskOfferingId() != null) {
|
||||
response.setDiskOfferingName(getManagementServer().findDiskOfferingById(volume.getDiskOfferingId()).getName());
|
||||
response.setDiskOfferingDisplayText(getManagementServer().findDiskOfferingById(volume.getDiskOfferingId()).getDisplayText());
|
||||
}
|
||||
response.setDomain(getManagementServer().findDomainIdById(volume.getDomainId()).getName());
|
||||
response.setStorageType("shared"); // NOTE: You can never create a local disk volume but if that changes, we need to change this
|
||||
if (volume.getPoolId() != null)
|
||||
response.setStorage(getManagementServer().findPoolById(volume.getPoolId()).getName());
|
||||
response.setZoneId(volume.getDataCenterId());
|
||||
response.setZoneName(getManagementServer().getDataCenterBy(volume.getDataCenterId()).getName());
|
||||
|
||||
try {
|
||||
long jobId = 0;
|
||||
if (useSnapshot) {
|
||||
jobId = getManagementServer().createVolumeFromSnapshotAsync(userId, account.getId(), snapshotId, name);
|
||||
} else {
|
||||
jobId = getManagementServer().createVolumeAsync(userId, account.getId(), name, zoneId, diskOfferingId, size);
|
||||
}
|
||||
|
||||
if (jobId == 0) {
|
||||
s_logger.warn("Unable to schedule async-job for CreateVolume command");
|
||||
} else {
|
||||
if(s_logger.isDebugEnabled())
|
||||
s_logger.debug("CreateVolume command has been accepted, job id: " + jobId);
|
||||
}
|
||||
|
||||
long volumeId = waitInstanceCreation(jobId);
|
||||
List<Pair<String, Object>> returnValues = new ArrayList<Pair<String, Object>>();
|
||||
returnValues.add(new Pair<String, Object>(BaseCmd.Properties.JOB_ID.getName(), Long.valueOf(jobId)));
|
||||
returnValues.add(new Pair<String, Object>(BaseCmd.Properties.VOLUME_ID.getName(), Long.valueOf(volumeId)));
|
||||
|
||||
return returnValues;
|
||||
} catch (Exception ex) {
|
||||
s_logger.error("Failed to create volume " + (useSnapshot ? ("from snapshot " + snapshotId) : ("in zone " + zoneId + " with disk offering " + diskOfferingId)), ex);
|
||||
if (useSnapshot) {
|
||||
throw new ServerApiException(BaseCmd.CREATE_VOLUME_FROM_SNAPSHOT_ERROR, "Unable to create a volume from snapshot with id " + snapshotId + " for this account.");
|
||||
} else {
|
||||
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to create volume: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return SerializerHelper.toSerializedString(response);
|
||||
}
|
||||
|
||||
protected long getInstanceIdFromJobSuccessResult(String result) {
|
||||
VolumeOperationResultObject resultObject = (VolumeOperationResultObject) SerializerHelper.fromSerializedString(result);
|
||||
if(resultObject != null) {
|
||||
return resultObject.getId();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,6 +28,7 @@ import com.cloud.api.commands.CreateDomainCmd;
|
||||
import com.cloud.api.commands.CreatePortForwardingServiceCmd;
|
||||
import com.cloud.api.commands.CreatePortForwardingServiceRuleCmd;
|
||||
import com.cloud.api.commands.CreateUserCmd;
|
||||
import com.cloud.api.commands.CreateVolumeCmd;
|
||||
import com.cloud.api.commands.DeletePortForwardingServiceCmd;
|
||||
import com.cloud.api.commands.DeleteUserCmd;
|
||||
import com.cloud.api.commands.DeployVMCmd;
|
||||
@ -348,19 +349,6 @@ public interface ManagementServer {
|
||||
*/
|
||||
Long getAccountIdForVlan(long vlanDbId);
|
||||
|
||||
/**
|
||||
* Creates a data volume
|
||||
* @param accountId
|
||||
* @pparam userId
|
||||
* @param name - name for the volume
|
||||
* @param zoneId - id of the zone to create this volume on
|
||||
* @param diskOfferingId - id of the disk offering to create this volume with
|
||||
* @param size - size of the volume
|
||||
* @return true if success, false if not
|
||||
*/
|
||||
VolumeVO createVolume(long accountId, long userId, String name, long zoneId, long diskOfferingId, long startEventId, long size) throws InternalErrorException;
|
||||
long createVolumeAsync(long accountId, long userId, String name, long zoneId, long diskOfferingId, long size) throws InvalidParameterValueException, InternalErrorException, ResourceAllocationException;
|
||||
|
||||
/**
|
||||
* Finds the root volume of the VM
|
||||
* @param vmId
|
||||
@ -1129,8 +1117,6 @@ public interface ManagementServer {
|
||||
*/
|
||||
boolean destroyTemplateSnapshot(Long userId, long snapshotId);
|
||||
|
||||
long createVolumeFromSnapshotAsync(long userId, long accountId, long snapshotId, String volumeName) throws InternalErrorException, ResourceAllocationException;
|
||||
|
||||
/**
|
||||
* List all snapshots of a disk volume. Optionaly lists snapshots created by specified interval
|
||||
* @param cmd the command containing the search criteria (order by, limit, etc.)
|
||||
@ -1409,7 +1395,6 @@ public interface ManagementServer {
|
||||
|
||||
boolean checkLocalStorageConfigVal();
|
||||
|
||||
boolean validateCustomVolumeSizeRange(long size) throws InvalidParameterValueException;
|
||||
boolean updateUser(UpdateUserCmd cmd) throws InvalidParameterValueException;
|
||||
boolean updateTemplatePermissions(UpdateTemplateOrIsoPermissionsCmd cmd)throws InvalidParameterValueException, PermissionDeniedException,InternalErrorException;
|
||||
String[] createApiKeyAndSecretKey(RegisterCmd cmd);
|
||||
|
||||
@ -59,7 +59,6 @@ import com.cloud.api.commands.CreateDomainCmd;
|
||||
import com.cloud.api.commands.CreatePortForwardingServiceCmd;
|
||||
import com.cloud.api.commands.CreatePortForwardingServiceRuleCmd;
|
||||
import com.cloud.api.commands.CreateUserCmd;
|
||||
import com.cloud.api.commands.CreateVolumeCmd;
|
||||
import com.cloud.api.commands.DeletePortForwardingServiceCmd;
|
||||
import com.cloud.api.commands.DeleteUserCmd;
|
||||
import com.cloud.api.commands.DeployVMCmd;
|
||||
@ -128,8 +127,6 @@ import com.cloud.async.executor.NetworkGroupIngressParam;
|
||||
import com.cloud.async.executor.SecurityGroupParam;
|
||||
import com.cloud.async.executor.VMOperationParam;
|
||||
import com.cloud.async.executor.VMOperationParam.VmOp;
|
||||
import com.cloud.async.executor.VolumeOperationParam;
|
||||
import com.cloud.async.executor.VolumeOperationParam.VolumeOp;
|
||||
import com.cloud.capacity.CapacityVO;
|
||||
import com.cloud.capacity.dao.CapacityDao;
|
||||
import com.cloud.configuration.ConfigurationManager;
|
||||
@ -376,8 +373,6 @@ public class ManagementServerImpl implements ManagementServer {
|
||||
|
||||
private boolean _isHypervisorSnapshotCapable = false;
|
||||
|
||||
private final int _maxVolumeSizeInGb;
|
||||
|
||||
protected ManagementServerImpl() {
|
||||
ComponentLocator locator = ComponentLocator.getLocator(Name);
|
||||
_lunDao = locator.getDao(PreallocatedLunDao.class);
|
||||
@ -471,11 +466,6 @@ public class ManagementServerImpl implements ManagementServer {
|
||||
// Parse the max number of UserVMs and public IPs from server-setup.xml,
|
||||
// and set them in the right places
|
||||
|
||||
String maxVolumeSizeInGbString = _configs.get("max.volume.size.gb");
|
||||
int maxVolumeSizeGb = NumbersUtil.parseInt(maxVolumeSizeInGbString, 2000);
|
||||
|
||||
_maxVolumeSizeInGb = maxVolumeSizeGb;
|
||||
|
||||
_routerRamSize = NumbersUtil.parseInt(_configs.get("router.ram.size"),NetworkManager.DEFAULT_ROUTER_VM_RAMSIZE);
|
||||
_proxyRamSize = NumbersUtil.parseInt(_configs.get("consoleproxy.ram.size"), ConsoleProxyManager.DEFAULT_PROXY_VM_RAMSIZE);
|
||||
_ssRamSize = NumbersUtil.parseInt(_configs.get("secstorage.ram.size"), SecondaryStorageVmManager.DEFAULT_SS_VM_RAMSIZE);
|
||||
@ -1399,104 +1389,6 @@ public class ManagementServerImpl implements ManagementServer {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VolumeVO createVolume(long userId, long accountId, String name, long zoneId, long diskOfferingId, long startEventId, long size) throws InternalErrorException {
|
||||
EventUtils.saveStartedEvent(userId, accountId, EventTypes.EVENT_VOLUME_CREATE, "Creating volume", startEventId);
|
||||
DataCenterVO zone = _dcDao.findById(zoneId);
|
||||
DiskOfferingVO diskOffering = _diskOfferingDao.findById(diskOfferingId);
|
||||
VolumeVO createdVolume = _storageMgr.createVolume(accountId, userId, name, zone, diskOffering, startEventId,size);
|
||||
|
||||
if (createdVolume != null)
|
||||
return createdVolume;
|
||||
else
|
||||
throw new InternalErrorException("Failed to create volume.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long createVolumeAsync(long userId, long accountId, String name, long zoneId, long diskOfferingId, long size) throws InvalidParameterValueException, InternalErrorException, ResourceAllocationException {
|
||||
// Check that the account is valid
|
||||
AccountVO account = _accountDao.findById(accountId);
|
||||
if (account == null) {
|
||||
throw new InvalidParameterValueException("Please specify a valid account.");
|
||||
}
|
||||
|
||||
// Check that the zone is valid
|
||||
DataCenterVO zone = _dcDao.findById(zoneId);
|
||||
if (zone == null) {
|
||||
throw new InvalidParameterValueException("Please specify a valid zone.");
|
||||
}
|
||||
|
||||
// Check that the the disk offering is specified
|
||||
DiskOfferingVO diskOffering = _diskOfferingDao.findById(diskOfferingId);
|
||||
if ((diskOffering == null) || !DiskOfferingVO.Type.Disk.equals(diskOffering.getType())) {
|
||||
throw new InvalidParameterValueException("Please specify a valid disk offering.");
|
||||
}
|
||||
|
||||
// Check that there is a shared primary storage pool in the specified zone
|
||||
List<StoragePoolVO> storagePools = _poolDao.listByDataCenterId(zoneId);
|
||||
boolean sharedPoolExists = false;
|
||||
for (StoragePoolVO storagePool : storagePools) {
|
||||
if (storagePool.isShared()) {
|
||||
sharedPoolExists = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that there is at least one host in the specified zone
|
||||
List<HostVO> hosts = _hostDao.listByDataCenter(zoneId);
|
||||
if (hosts.isEmpty()) {
|
||||
throw new InvalidParameterValueException("Please add a host in the specified zone before creating a new volume.");
|
||||
}
|
||||
|
||||
if (!sharedPoolExists) {
|
||||
throw new InvalidParameterValueException("Please specify a zone that has at least one shared primary storage pool.");
|
||||
}
|
||||
|
||||
// Check that the resource limit for volumes won't be exceeded
|
||||
if (_accountMgr.resourceLimitExceeded(account, ResourceType.volume)) {
|
||||
ResourceAllocationException rae = new ResourceAllocationException("Maximum number of volumes for account: " + account.getAccountName() + " has been exceeded.");
|
||||
rae.setResourceType("volume");
|
||||
throw rae;
|
||||
}
|
||||
|
||||
long eventId = EventUtils.saveScheduledEvent(userId, accountId, EventTypes.EVENT_VOLUME_CREATE, "creating volume");
|
||||
|
||||
VolumeOperationParam param = new VolumeOperationParam();
|
||||
param.setOp(VolumeOp.Create);
|
||||
param.setAccountId(accountId);
|
||||
param.setUserId(UserContext.current().getUserId());
|
||||
param.setName(name);
|
||||
param.setZoneId(zoneId);
|
||||
param.setDiskOfferingId(diskOfferingId);
|
||||
param.setEventId(eventId);
|
||||
param.setSize(size);
|
||||
|
||||
Gson gson = GsonHelper.getBuilder().create();
|
||||
|
||||
AsyncJobVO job = new AsyncJobVO();
|
||||
job.setUserId(UserContext.current().getUserId());
|
||||
job.setAccountId(accountId);
|
||||
job.setCmd("VolumeOperation");
|
||||
job.setCmdInfo(gson.toJson(param));
|
||||
job.setCmdOriginator(CreateVolumeCmd.getResultObjectName());
|
||||
|
||||
return _asyncMgr.submitAsyncJob(job);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long createVolumeFromSnapshotAsync(long userId, long accountId, long snapshotId, String volumeName) throws InternalErrorException, ResourceAllocationException {
|
||||
SnapshotVO snapshot = _snapshotDao.findById(snapshotId);
|
||||
AccountVO account = _accountDao.findById(snapshot.getAccountId());
|
||||
|
||||
// Check that the resource limit for volumes won't be exceeded
|
||||
if (_accountMgr.resourceLimitExceeded(account, ResourceType.volume)) {
|
||||
ResourceAllocationException rae = new ResourceAllocationException("Maximum number of volumes for account: " + account.getAccountName() + " has been exceeded.");
|
||||
rae.setResourceType("volume");
|
||||
throw rae;
|
||||
}
|
||||
|
||||
return _snapMgr.createVolumeFromSnapshotAsync(userId, accountId, snapshotId, volumeName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VolumeVO findRootVolume(long vmId) {
|
||||
List<VolumeVO> volumes = _volumeDao.findByInstanceAndType(vmId, VolumeType.ROOT);
|
||||
@ -6859,17 +6751,6 @@ public class ManagementServerImpl implements ManagementServer {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateCustomVolumeSizeRange(long size) throws InvalidParameterValueException {
|
||||
if (size<0 || (size>0 && size < 1)) {
|
||||
throw new InvalidParameterValueException("Please specify a size of at least 1 Gb.");
|
||||
} else if (size > _maxVolumeSizeInGb) {
|
||||
throw new InvalidParameterValueException("The maximum size allowed is " + _maxVolumeSizeInGb + " Gb.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean lockAccount(LockAccountCmd cmd) {
|
||||
|
||||
|
||||
@ -24,6 +24,7 @@ import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.Command;
|
||||
import com.cloud.api.commands.CancelPrimaryStorageMaintenanceCmd;
|
||||
import com.cloud.api.commands.CreateStoragePoolCmd;
|
||||
import com.cloud.api.commands.CreateVolumeCmd;
|
||||
import com.cloud.api.commands.DeletePoolCmd;
|
||||
import com.cloud.api.commands.DeleteVolumeCmd;
|
||||
import com.cloud.api.commands.PreparePrimaryStorageForMaintenanceCmd;
|
||||
@ -32,6 +33,7 @@ import com.cloud.dc.DataCenterVO;
|
||||
import com.cloud.dc.HostPodVO;
|
||||
import com.cloud.exception.InternalErrorException;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.exception.PermissionDeniedException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.exception.ResourceInUseException;
|
||||
import com.cloud.exception.StorageUnavailableException;
|
||||
@ -191,19 +193,23 @@ public interface StorageManager extends Manager {
|
||||
* @return VolumeVO
|
||||
*/
|
||||
VolumeVO moveVolume(VolumeVO volume, long destPoolDcId, Long destPoolPodId, Long destPoolClusterId) throws InternalErrorException;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new volume in a pool in the specified zone
|
||||
* @param accountId
|
||||
* @param userId
|
||||
* @param name
|
||||
* @param dc
|
||||
* @param diskOffering
|
||||
* @param size
|
||||
* @return VolumeVO
|
||||
* Creates the database object for a volume based on the given criteria
|
||||
* @param cmd the API command wrapping the criteria (account/domainId [admin only], zone, diskOffering, snapshot, name)
|
||||
* @return the volume object
|
||||
* @throws InvalidParameterValueException
|
||||
* @throws PermissionDeniedException
|
||||
*/
|
||||
VolumeVO createVolume(long accountId, long userId, String name, DataCenterVO dc, DiskOfferingVO diskOffering, long startEventId, long size);
|
||||
|
||||
VolumeVO createVolumeDB(CreateVolumeCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, ResourceAllocationException;
|
||||
|
||||
/**
|
||||
* Creates the volume based on the given criteria
|
||||
* @param cmd the API command wrapping the criteria (account/domainId [admin only], zone, diskOffering, snapshot, name)
|
||||
* @return the volume object
|
||||
*/
|
||||
VolumeVO createVolume(CreateVolumeCmd cmd);
|
||||
|
||||
/**
|
||||
* Marks the specified volume as destroyed in the management server database. The expunge thread will delete the volume from its storage pool.
|
||||
* @param volume
|
||||
@ -270,11 +276,6 @@ public interface StorageManager extends Manager {
|
||||
List<StoragePoolVO> getStoragePoolsForVm(long vmId);
|
||||
|
||||
String getPrimaryStorageNameLabel(VolumeVO volume);
|
||||
|
||||
/**
|
||||
* Creates a volume from the specified snapshot. A new volume is returned which is not attached to any VM Instance
|
||||
*/
|
||||
VolumeVO createVolumeFromSnapshot(long userId, long accountId, long snapshotId, String volumeName, long startEventId);
|
||||
|
||||
/**
|
||||
* Enable maintenance for primary storage
|
||||
|
||||
@ -65,6 +65,7 @@ import com.cloud.api.BaseCmd;
|
||||
import com.cloud.api.ServerApiException;
|
||||
import com.cloud.api.commands.CancelPrimaryStorageMaintenanceCmd;
|
||||
import com.cloud.api.commands.CreateStoragePoolCmd;
|
||||
import com.cloud.api.commands.CreateVolumeCmd;
|
||||
import com.cloud.api.commands.DeletePoolCmd;
|
||||
import com.cloud.api.commands.DeleteVolumeCmd;
|
||||
import com.cloud.api.commands.PreparePrimaryStorageForMaintenanceCmd;
|
||||
@ -97,6 +98,7 @@ import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.InternalErrorException;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.exception.OperationTimedoutException;
|
||||
import com.cloud.exception.PermissionDeniedException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.exception.ResourceInUseException;
|
||||
import com.cloud.exception.StorageUnavailableException;
|
||||
@ -132,6 +134,7 @@ import com.cloud.storage.snapshot.SnapshotScheduler;
|
||||
import com.cloud.template.TemplateManager;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountManager;
|
||||
import com.cloud.user.AccountVO;
|
||||
import com.cloud.user.User;
|
||||
import com.cloud.user.UserContext;
|
||||
import com.cloud.user.dao.AccountDao;
|
||||
@ -212,6 +215,7 @@ public class StorageManagerImpl implements StorageManager {
|
||||
protected int _pingInterval = 60; // seconds
|
||||
protected int _hostRetry;
|
||||
protected int _overProvisioningFactor = 1;
|
||||
private int _maxVolumeSizeInGb;
|
||||
|
||||
private int _totalRetries;
|
||||
private int _pauseInterval;
|
||||
@ -396,16 +400,16 @@ public class StorageManagerImpl implements StorageManager {
|
||||
return answers[0];
|
||||
}
|
||||
|
||||
protected DiskCharacteristicsTO createDiskCharacteristics(VolumeVO volume, VMTemplateVO template, DataCenterVO dc, DiskOfferingVO diskOffering) {
|
||||
private DiskCharacteristicsTO createDiskCharacteristics(VolumeVO volume, VMTemplateVO template, long dataCenterId, DiskOfferingVO diskOffering) {
|
||||
if (volume.getVolumeType() == VolumeType.ROOT && Storage.ImageFormat.ISO != template.getFormat()) {
|
||||
SearchCriteria<VMTemplateHostVO> sc = HostTemplateStatesSearch.create();
|
||||
sc.setParameters("id", template.getId());
|
||||
sc.setParameters("state", com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOADED);
|
||||
sc.setJoinParameters("host", "dcId", dc.getId());
|
||||
sc.setJoinParameters("host", "dcId", dataCenterId);
|
||||
|
||||
List<VMTemplateHostVO> sss = _vmTemplateHostDao.search(sc, null);
|
||||
if (sss.size() == 0) {
|
||||
throw new CloudRuntimeException("Template " + template.getName() + " has not been completely downloaded to zone " + dc.getId());
|
||||
throw new CloudRuntimeException("Template " + template.getName() + " has not been completely downloaded to zone " + dataCenterId);
|
||||
}
|
||||
VMTemplateHostVO ss = sss.get(0);
|
||||
|
||||
@ -427,43 +431,14 @@ public class StorageManagerImpl implements StorageManager {
|
||||
}
|
||||
|
||||
@DB
|
||||
protected Pair<VolumeVO, String> createVolumeFromSnapshot(long userId, long accountId, String userSpecifiedName, DataCenterVO dc, DiskOfferingVO diskOffering, SnapshotVO snapshot, String templatePath, Long originalVolumeSize, VMTemplateVO template) {
|
||||
|
||||
private Pair<VolumeVO, String> createVolumeFromSnapshot(VolumeVO volume, SnapshotVO snapshot, String templatePath, Long originalVolumeSize, VMTemplateVO template) {
|
||||
VolumeVO createdVolume = null;
|
||||
Long volumeId = null;
|
||||
|
||||
String volumeFolder = null;
|
||||
|
||||
// Create the Volume object and save it so that we can return it to the user
|
||||
Account account = _accountDao.findById(accountId);
|
||||
VolumeVO volume = new VolumeVO(null, userSpecifiedName, -1, -1, -1, -1, new Long(-1), null, null, 0, Volume.VolumeType.DATADISK);
|
||||
volume.setPoolId(null);
|
||||
volume.setDataCenterId(dc.getId());
|
||||
volume.setPodId(null);
|
||||
volume.setAccountId(accountId);
|
||||
volume.setDomainId(account.getDomainId().longValue());
|
||||
volume.setMirrorState(MirrorState.NOT_MIRRORED);
|
||||
if (diskOffering != null) {
|
||||
volume.setDiskOfferingId(diskOffering.getId());
|
||||
}
|
||||
volume.setSize(originalVolumeSize);
|
||||
volume.setStorageResourceType(StorageResourceType.STORAGE_POOL);
|
||||
volume.setInstanceId(null);
|
||||
volume.setUpdated(new Date());
|
||||
volume.setStatus(AsyncInstanceCreateStatus.Creating);
|
||||
volume = _volsDao.persist(volume);
|
||||
volumeId = volume.getId();
|
||||
|
||||
AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor.getCurrentExecutor();
|
||||
if(asyncExecutor != null) {
|
||||
AsyncJobVO job = asyncExecutor.getJob();
|
||||
|
||||
if(s_logger.isInfoEnabled())
|
||||
s_logger.info("CreateVolume created a new instance " + volumeId + ", update async job-" + job.getId() + " progress status");
|
||||
|
||||
_asyncMgr.updateAsyncJobAttachment(job.getId(), "volume", volumeId);
|
||||
_asyncMgr.updateAsyncJobStatus(job.getId(), BaseCmd.PROGRESS_INSTANCE_CREATED, volumeId);
|
||||
}
|
||||
Account account = _accountDao.findById(volume.getAccountId());
|
||||
|
||||
final HashSet<StoragePool> poolsToAvoid = new HashSet<StoragePool>();
|
||||
StoragePoolVO pool = null;
|
||||
@ -472,10 +447,10 @@ public class StorageManagerImpl implements StorageManager {
|
||||
Pair<HostPodVO, Long> pod = null;
|
||||
String volumeUUID = null;
|
||||
String details = null;
|
||||
|
||||
DiskCharacteristicsTO dskCh = createDiskCharacteristics(volume, template, dc, diskOffering);
|
||||
|
||||
|
||||
DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId());
|
||||
DataCenterVO dc = _dcDao.findById(volume.getDataCenterId());
|
||||
DiskCharacteristicsTO dskCh = createDiskCharacteristics(volume, template, dc.getId(), diskOffering);
|
||||
|
||||
// Determine what pod to store the volume in
|
||||
while ((pod = _agentMgr.findPod(null, null, dc, account.getId(), podsToAvoid)) != null) {
|
||||
// Determine what storage pool to store the volume in
|
||||
@ -484,13 +459,13 @@ public class StorageManagerImpl implements StorageManager {
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Attempting to create volume from snapshotId: " + snapshot.getId() + " on storage pool " + pool.getName());
|
||||
}
|
||||
|
||||
|
||||
// Get the newly created VDI from the snapshot.
|
||||
// This will return a null volumePath if it could not be created
|
||||
Pair<String, String> volumeDetails = createVDIFromSnapshot(userId, snapshot, pool, templatePath);
|
||||
Pair<String, String> volumeDetails = createVDIFromSnapshot(UserContext.current().getUserId(), snapshot, pool, templatePath);
|
||||
volumeUUID = volumeDetails.first();
|
||||
details = volumeDetails.second();
|
||||
|
||||
|
||||
if (volumeUUID != null) {
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Volume with UUID " + volumeUUID + " was created on storage pool " + pool.getName());
|
||||
@ -500,7 +475,6 @@ public class StorageManagerImpl implements StorageManager {
|
||||
}
|
||||
|
||||
s_logger.warn("Unable to create volume on pool " + pool.getName() + ", reason: " + details);
|
||||
|
||||
}
|
||||
|
||||
if (success) {
|
||||
@ -517,7 +491,7 @@ public class StorageManagerImpl implements StorageManager {
|
||||
|
||||
if (success) {
|
||||
// Increment the number of volumes
|
||||
_accountMgr.incrementResourceCount(accountId, ResourceType.volume);
|
||||
_accountMgr.incrementResourceCount(account.getId(), ResourceType.volume);
|
||||
|
||||
createdVolume.setStatus(AsyncInstanceCreateStatus.Created);
|
||||
createdVolume.setPodId(pod.first().getId());
|
||||
@ -536,19 +510,17 @@ public class StorageManagerImpl implements StorageManager {
|
||||
return new Pair<VolumeVO, String>(createdVolume, details);
|
||||
}
|
||||
|
||||
@Override
|
||||
@DB
|
||||
public VolumeVO createVolumeFromSnapshot(long userId, long accountId, long snapshotId, String volumeName, long startEventId) {
|
||||
|
||||
private VolumeVO createVolumeFromSnapshot(VolumeVO volume, long snapshotId/*, long startEventId*/) {
|
||||
// FIXME: start event id needs to come from somewhere
|
||||
EventVO event = new EventVO();
|
||||
event.setUserId(userId);
|
||||
event.setAccountId(accountId);
|
||||
event.setUserId(UserContext.current().getUserId());
|
||||
event.setAccountId(volume.getAccountId());
|
||||
event.setType(EventTypes.EVENT_VOLUME_CREATE);
|
||||
event.setState(EventState.Started);
|
||||
event.setStartId(startEventId);
|
||||
// FIXME: event.setStartId(startEventId);
|
||||
event.setDescription("Creating volume from snapshot with id: "+snapshotId);
|
||||
_eventDao.persist(event);
|
||||
|
||||
|
||||
// By default, assume failure.
|
||||
VolumeVO createdVolume = null;
|
||||
String details = null;
|
||||
@ -612,7 +584,7 @@ public class StorageManagerImpl implements StorageManager {
|
||||
s_logger.error("Original volume must have been a ROOT DISK or a DATA DISK");
|
||||
return null;
|
||||
}
|
||||
Pair<VolumeVO, String> volumeDetails = createVolumeFromSnapshot(userId, accountId, volumeName, dc, diskOffering, snapshot, templatePath, originalVolume.getSize(), template);
|
||||
Pair<VolumeVO, String> volumeDetails = createVolumeFromSnapshot(volume, snapshot, templatePath, originalVolume.getSize(), template);
|
||||
createdVolume = volumeDetails.first();
|
||||
if (createdVolume != null) {
|
||||
volumeId = createdVolume.getId();
|
||||
@ -636,11 +608,11 @@ public class StorageManagerImpl implements StorageManager {
|
||||
String poolName = _storagePoolDao.findById(createdVolume.getPoolId()).getName();
|
||||
String eventParams = "id=" + volumeId +"\ndoId="+diskOfferingId+"\ntId="+templateId+"\ndcId="+originalVolume.getDataCenterId()+"\nsize="+sizeMB;
|
||||
event = new EventVO();
|
||||
event.setAccountId(accountId);
|
||||
event.setUserId(userId);
|
||||
event.setAccountId(volume.getAccountId());
|
||||
event.setUserId(UserContext.current().getUserId());
|
||||
event.setType(EventTypes.EVENT_VOLUME_CREATE);
|
||||
event.setParameters(eventParams);
|
||||
event.setStartId(startEventId);
|
||||
// FIXME: event.setStartId(startEventId);
|
||||
event.setState(EventState.Completed);
|
||||
if (createdVolume.getPath() != null) {
|
||||
event.setDescription("Created volume: "+ createdVolume.getName() + " with size: " + sizeMB + " MB in pool: " + poolName + " from snapshot id: " + snapshotId);
|
||||
@ -703,9 +675,9 @@ public class StorageManagerImpl implements StorageManager {
|
||||
|
||||
DiskCharacteristicsTO dskCh = null;
|
||||
if (volume.getVolumeType() == VolumeType.ROOT && Storage.ImageFormat.ISO != template.getFormat()) {
|
||||
dskCh = createDiskCharacteristics(volume, template, dc, offering);
|
||||
dskCh = createDiskCharacteristics(volume, template, dc.getId(), offering);
|
||||
} else {
|
||||
dskCh = createDiskCharacteristics(volume, template, dc, diskOffering);
|
||||
dskCh = createDiskCharacteristics(volume, template, dc.getId(), diskOffering);
|
||||
}
|
||||
|
||||
Transaction txn = Transaction.currentTxn();
|
||||
@ -1572,92 +1544,197 @@ public class StorageManagerImpl implements StorageManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
@DB
|
||||
public VolumeVO createVolume(long accountId, long userId, String userSpecifiedName, DataCenterVO dc, DiskOfferingVO diskOffering, long startEventId, long size)
|
||||
{
|
||||
String volumeName = "";
|
||||
VolumeVO createdVolume = null;
|
||||
|
||||
try
|
||||
{
|
||||
// Determine the volume's name
|
||||
volumeName = getRandomVolumeName();
|
||||
|
||||
// Create the Volume object and save it so that we can return it to the user
|
||||
Account account = _accountDao.findById(accountId);
|
||||
VolumeVO volume = new VolumeVO(null, userSpecifiedName, -1, -1, -1, -1, new Long(-1), null, null, 0, Volume.VolumeType.DATADISK);
|
||||
volume.setPoolId(null);
|
||||
volume.setDataCenterId(dc.getId());
|
||||
volume.setPodId(null);
|
||||
volume.setAccountId(accountId);
|
||||
volume.setDomainId(account.getDomainId().longValue());
|
||||
volume.setMirrorState(MirrorState.NOT_MIRRORED);
|
||||
volume.setDiskOfferingId(diskOffering.getId());
|
||||
volume.setStorageResourceType(StorageResourceType.STORAGE_POOL);
|
||||
volume.setInstanceId(null);
|
||||
volume.setUpdated(new Date());
|
||||
volume.setStatus(AsyncInstanceCreateStatus.Creating);
|
||||
volume.setDomainId(account.getDomainId().longValue());
|
||||
volume = _volsDao.persist(volume);
|
||||
|
||||
AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor.getCurrentExecutor();
|
||||
if (asyncExecutor != null) {
|
||||
AsyncJobVO job = asyncExecutor.getJob();
|
||||
|
||||
if (s_logger.isInfoEnabled())
|
||||
s_logger.info("CreateVolume created a new instance " + volume.getId() + ", update async job-" + job.getId() + " progress status");
|
||||
|
||||
_asyncMgr.updateAsyncJobAttachment(job.getId(), "volume", volume.getId());
|
||||
_asyncMgr.updateAsyncJobStatus(job.getId(), BaseCmd.PROGRESS_INSTANCE_CREATED, volume.getId());
|
||||
}
|
||||
|
||||
List<StoragePoolVO> poolsToAvoid = new ArrayList<StoragePoolVO>();
|
||||
Set<Long> podsToAvoid = new HashSet<Long>();
|
||||
Pair<HostPodVO, Long> pod = null;
|
||||
|
||||
while ((pod = _agentMgr.findPod(null, null, dc, account.getId(), podsToAvoid)) != null) {
|
||||
if ((createdVolume = createVolume(volume, null, null, dc, pod.first(), null, null, diskOffering, poolsToAvoid, size)) != null) {
|
||||
break;
|
||||
} else {
|
||||
podsToAvoid.add(pod.first().getId());
|
||||
}
|
||||
}
|
||||
|
||||
// Create an event
|
||||
EventVO event = new EventVO();
|
||||
event.setAccountId(accountId);
|
||||
event.setUserId(userId);
|
||||
event.setType(EventTypes.EVENT_VOLUME_CREATE);
|
||||
event.setStartId(startEventId);
|
||||
|
||||
Transaction txn = Transaction.currentTxn();
|
||||
public VolumeVO createVolumeDB(CreateVolumeCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, ResourceAllocationException {
|
||||
// FIXME: some of the scheduled event stuff might be missing here...
|
||||
Account account = (Account)UserContext.current().getAccountObject();
|
||||
String accountName = cmd.getAccountName();
|
||||
Long domainId = cmd.getDomainId();
|
||||
Account targetAccount = null;
|
||||
if ((account == null) || isAdmin(account.getType())) {
|
||||
// Admin API call
|
||||
if ((domainId != null) && (accountName != null)) {
|
||||
if ((account != null) && !_domainDao.isChildDomain(account.getDomainId(), domainId)) {
|
||||
throw new PermissionDeniedException("Unable to create volume in domain " + domainId + ", permission denied.");
|
||||
}
|
||||
|
||||
txn.start();
|
||||
|
||||
if (createdVolume != null) {
|
||||
// Increment the number of volumes
|
||||
_accountMgr.incrementResourceCount(accountId, ResourceType.volume);
|
||||
|
||||
// Set event parameters
|
||||
long sizeMB = createdVolume.getSize() / (1024 * 1024);
|
||||
StoragePoolVO pool = _storagePoolDao.findById(createdVolume.getPoolId());
|
||||
String eventParams = "id=" + createdVolume.getId() + "\ndoId=" + diskOffering.getId() + "\ntId=" + -1 + "\ndcId=" + dc.getId() + "\nsize=" + sizeMB;
|
||||
event.setLevel(EventVO.LEVEL_INFO);
|
||||
event.setDescription("Created volume: " + createdVolume.getName() + " with size: " + sizeMB + " MB in pool: " + pool.getName());
|
||||
event.setParameters(eventParams);
|
||||
_eventDao.persist(event);
|
||||
targetAccount = _accountDao.findActiveAccount(accountName, domainId);
|
||||
} else {
|
||||
// Mark the existing volume record as corrupted
|
||||
volume.setStatus(AsyncInstanceCreateStatus.Corrupted);
|
||||
volume.setDestroyed(true);
|
||||
_volsDao.update(volume.getId(), volume);
|
||||
}
|
||||
targetAccount = account;
|
||||
}
|
||||
|
||||
txn.commit();
|
||||
} catch (Exception e) {
|
||||
s_logger.error("Unhandled exception while saving volume " + volumeName, e);
|
||||
// If the account is null, this means that the accountName and domainId passed in were invalid
|
||||
if (targetAccount == null) {
|
||||
throw new InvalidParameterValueException("Unable to find account with name: " + accountName + " and domain ID: " + domainId);
|
||||
}
|
||||
} else {
|
||||
targetAccount = account;
|
||||
}
|
||||
|
||||
// check if the volume can be created for the user
|
||||
// Check that the resource limit for volumes won't be exceeded
|
||||
if (_accountMgr.resourceLimitExceeded((AccountVO)targetAccount, ResourceType.volume)) {
|
||||
ResourceAllocationException rae = new ResourceAllocationException("Maximum number of volumes for account: " + targetAccount.getAccountName() + " has been exceeded.");
|
||||
rae.setResourceType("volume");
|
||||
throw rae;
|
||||
}
|
||||
|
||||
// validate input parameters before creating the volume
|
||||
if (cmd.getSnapshotId() == null) {
|
||||
Long zoneId = cmd.getZoneId();
|
||||
if ((zoneId == null)) {
|
||||
throw new InvalidParameterValueException("Missing parameter, zoneid must be specified.");
|
||||
}
|
||||
|
||||
Long diskOfferingId = cmd.getDiskOfferingId();
|
||||
Long size = cmd.getSize();
|
||||
if ((diskOfferingId == null) && (size == null)) {
|
||||
throw new InvalidParameterValueException("Missing parameter(s),either a positive volume size or a valid disk offering id must be specified.");
|
||||
} else if ((diskOfferingId == null) && (size != null)) {
|
||||
boolean ok = validateCustomVolumeSizeRange(size);
|
||||
|
||||
if (!ok) {
|
||||
throw new InvalidParameterValueException("Invalid size for custom volume creation: " + size);
|
||||
}
|
||||
|
||||
//this is the case of creating var size vol with private disk offering
|
||||
List<DiskOfferingVO> privateTemplateList = _diskOfferingDao.findPrivateDiskOffering();
|
||||
diskOfferingId = privateTemplateList.get(0).getId(); //we use this id for creating volume
|
||||
} else {
|
||||
// Check that the the disk offering is specified
|
||||
DiskOfferingVO diskOffering = _diskOfferingDao.findById(diskOfferingId);
|
||||
if ((diskOffering == null) || !DiskOfferingVO.Type.Disk.equals(diskOffering.getType())) {
|
||||
throw new InvalidParameterValueException("Please specify a valid disk offering.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Long snapshotId = cmd.getSnapshotId();
|
||||
Snapshot snapshotCheck = _snapshotDao.findById(snapshotId);
|
||||
if (snapshotCheck == null) {
|
||||
throw new ServerApiException (BaseCmd.SNAPSHOT_INVALID_PARAM_ERROR, "unable to find a snapshot with id " + snapshotId);
|
||||
}
|
||||
|
||||
if (account != null) {
|
||||
if (isAdmin(account.getType())) {
|
||||
Account snapshotOwner = _accountDao.findById(snapshotCheck.getAccountId());
|
||||
if (!_domainDao.isChildDomain(account.getDomainId(), snapshotOwner.getDomainId())) {
|
||||
throw new ServerApiException(BaseCmd.ACCOUNT_ERROR, "Unable to create volume from snapshot with id " + snapshotId + ", permission denied.");
|
||||
}
|
||||
} else if (account.getId().longValue() != snapshotCheck.getAccountId()) {
|
||||
throw new ServerApiException(BaseCmd.SNAPSHOT_INVALID_PARAM_ERROR, "unable to find a snapshot with id " + snapshotId + " for this account");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Long zoneId = cmd.getZoneId();
|
||||
// Check that the zone is valid
|
||||
DataCenterVO zone = _dcDao.findById(zoneId);
|
||||
if (zone == null) {
|
||||
throw new InvalidParameterValueException("Please specify a valid zone.");
|
||||
}
|
||||
|
||||
// Check that there is a shared primary storage pool in the specified zone
|
||||
List<StoragePoolVO> storagePools = _storagePoolDao.listByDataCenterId(zoneId);
|
||||
boolean sharedPoolExists = false;
|
||||
for (StoragePoolVO storagePool : storagePools) {
|
||||
if (storagePool.isShared()) {
|
||||
sharedPoolExists = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that there is at least one host in the specified zone
|
||||
List<HostVO> hosts = _hostDao.listByDataCenter(zoneId);
|
||||
if (hosts.isEmpty()) {
|
||||
throw new InvalidParameterValueException("Please add a host in the specified zone before creating a new volume.");
|
||||
}
|
||||
|
||||
if (!sharedPoolExists) {
|
||||
throw new InvalidParameterValueException("Please specify a zone that has at least one shared primary storage pool.");
|
||||
}
|
||||
|
||||
String userSpecifiedName = cmd.getVolumeName();
|
||||
if (userSpecifiedName == null) {
|
||||
userSpecifiedName = getRandomVolumeName();
|
||||
}
|
||||
|
||||
VolumeVO volume = new VolumeVO(null, userSpecifiedName, -1, -1, -1, -1, new Long(-1), null, null, 0, Volume.VolumeType.DATADISK);
|
||||
volume.setPoolId(null);
|
||||
volume.setDataCenterId(zoneId);
|
||||
volume.setPodId(null);
|
||||
volume.setAccountId(targetAccount.getId());
|
||||
volume.setDomainId(account.getDomainId().longValue());
|
||||
volume.setMirrorState(MirrorState.NOT_MIRRORED);
|
||||
volume.setDiskOfferingId(cmd.getDiskOfferingId());
|
||||
volume.setStorageResourceType(StorageResourceType.STORAGE_POOL);
|
||||
volume.setInstanceId(null);
|
||||
volume.setUpdated(new Date());
|
||||
volume.setStatus(AsyncInstanceCreateStatus.Creating);
|
||||
volume.setDomainId(account.getDomainId().longValue());
|
||||
volume = _volsDao.persist(volume);
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
@Override @DB
|
||||
public VolumeVO createVolume(CreateVolumeCmd cmd) {
|
||||
VolumeVO createdVolume = _volsDao.findById(cmd.getId());
|
||||
Long userId = UserContext.current().getUserId();
|
||||
|
||||
if (cmd.getSnapshotId() != null) {
|
||||
return createVolumeFromSnapshot(createdVolume, cmd.getSnapshotId());
|
||||
} else {
|
||||
DataCenterVO dc = _dcDao.findById(cmd.getZoneId());
|
||||
DiskOfferingVO diskOffering = _diskOfferingDao.findById(cmd.getDiskOfferingId());
|
||||
long size = diskOffering.getDiskSize();
|
||||
|
||||
try {
|
||||
List<StoragePoolVO> poolsToAvoid = new ArrayList<StoragePoolVO>();
|
||||
Set<Long> podsToAvoid = new HashSet<Long>();
|
||||
Pair<HostPodVO, Long> pod = null;
|
||||
|
||||
while ((pod = _agentMgr.findPod(null, null, dc, createdVolume.getAccountId(), podsToAvoid)) != null) {
|
||||
if ((createdVolume = createVolume(createdVolume, null, null, dc, pod.first(), null, null, diskOffering, poolsToAvoid, size)) != null) {
|
||||
break;
|
||||
} else {
|
||||
podsToAvoid.add(pod.first().getId());
|
||||
}
|
||||
}
|
||||
|
||||
// Create an event
|
||||
EventVO event = new EventVO();
|
||||
event.setAccountId(createdVolume.getAccountId());
|
||||
event.setUserId(userId);
|
||||
event.setType(EventTypes.EVENT_VOLUME_CREATE);
|
||||
event.setStartId(startEventId); // FIX other event stuff as well for createVolume
|
||||
|
||||
Transaction txn = Transaction.currentTxn();
|
||||
|
||||
txn.start();
|
||||
|
||||
if (createdVolume != null) {
|
||||
// Increment the number of volumes
|
||||
_accountMgr.incrementResourceCount(createdVolume.getAccountId(), ResourceType.volume);
|
||||
|
||||
// Set event parameters
|
||||
long sizeMB = createdVolume.getSize() / (1024 * 1024);
|
||||
StoragePoolVO pool = _storagePoolDao.findById(createdVolume.getPoolId());
|
||||
String eventParams = "id=" + createdVolume.getId() + "\ndoId=" + diskOffering.getId() + "\ntId=" + -1 + "\ndcId=" + dc.getId() + "\nsize=" + sizeMB;
|
||||
event.setLevel(EventVO.LEVEL_INFO);
|
||||
event.setDescription("Created volume: " + createdVolume.getName() + " with size: " + sizeMB + " MB in pool: " + pool.getName());
|
||||
event.setParameters(eventParams);
|
||||
_eventDao.persist(event);
|
||||
} else {
|
||||
// Mark the existing volume record as corrupted
|
||||
createdVolume.setStatus(AsyncInstanceCreateStatus.Corrupted);
|
||||
createdVolume.setDestroyed(true);
|
||||
_volsDao.update(createdVolume.getId(), createdVolume);
|
||||
}
|
||||
|
||||
txn.commit();
|
||||
} catch (Exception e) {
|
||||
s_logger.error("Unhandled exception while creating volume " + createdVolume.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
return createdVolume;
|
||||
}
|
||||
|
||||
@ -2333,4 +2410,14 @@ public class StorageManagerImpl implements StorageManager {
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private boolean validateCustomVolumeSizeRange(long size) throws InvalidParameterValueException {
|
||||
if (size<0 || (size>0 && size < 1)) {
|
||||
throw new InvalidParameterValueException("Please specify a size of at least 1 Gb.");
|
||||
} else if (size > _maxVolumeSizeInGb) {
|
||||
throw new InvalidParameterValueException("The maximum size allowed is " + _maxVolumeSizeInGb + " Gb.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -71,11 +71,6 @@ public interface SnapshotManager extends Manager {
|
||||
*/
|
||||
SnapshotVO createSnapshotImpl(long volumeId, List<Long> policyIds) throws InvalidParameterValueException, ResourceAllocationException, InternalErrorException;
|
||||
|
||||
/**
|
||||
* Creates a volume from the specified snapshot. A new volume is returned which is not attached to any VM Instance
|
||||
*/
|
||||
long createVolumeFromSnapshotAsync(long userId, long accountId, long snapshotId, String volumeName) throws InternalErrorException;
|
||||
|
||||
/**
|
||||
* Destroys the specified snapshot from secondary storage
|
||||
*/
|
||||
|
||||
@ -1087,36 +1087,6 @@ public class SnapshotManagerImpl implements SnapshotManager {
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long createVolumeFromSnapshotAsync(long userId, long accountId, long snapshotId, String volumeName) throws InternalErrorException {
|
||||
// Precondition the snapshot is valid
|
||||
SnapshotVO snapshot = _snapshotDao.findById(snapshotId);
|
||||
VolumeVO volume = _volsDao.findById(snapshot.getVolumeId());
|
||||
|
||||
EventVO event = new EventVO();
|
||||
event.setUserId(userId);
|
||||
event.setAccountId(accountId);
|
||||
event.setType(EventTypes.EVENT_VOLUME_CREATE);
|
||||
event.setState(EventState.Scheduled);
|
||||
event.setDescription("Scheduled async job for creating volume from snapshot with id: "+snapshotId);
|
||||
event = _eventDao.persist(event);
|
||||
|
||||
SnapshotOperationParam param = new SnapshotOperationParam(userId, accountId, volume.getId(), snapshotId, volumeName);
|
||||
param.setEventId(event.getId());
|
||||
Gson gson = GsonHelper.getBuilder().create();
|
||||
|
||||
AsyncJobVO job = new AsyncJobVO();
|
||||
job.setUserId(userId);
|
||||
job.setAccountId(snapshot.getAccountId());
|
||||
job.setCmd("CreateVolumeFromSnapshot");
|
||||
job.setCmdInfo(gson.toJson(param));
|
||||
job.setCmdOriginator(CreateVolumeCmd.getResultObjectName());
|
||||
|
||||
return _asyncMgr.submitAsyncJob(job);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean deleteSnapshotDirsForAccount(long accountId) {
|
||||
|
||||
@ -1531,6 +1501,12 @@ public class SnapshotManagerImpl implements SnapshotManager {
|
||||
PoliciesForSnapSearch.join("policyRef", policyRefSearch, policyRefSearch.entity().getPolicyId(), PoliciesForSnapSearch.entity().getId());
|
||||
policyRefSearch.done();
|
||||
PoliciesForSnapSearch.done();
|
||||
|
||||
String maxVolumeSizeInGbString = configDao.get("max.volume.size.gb");
|
||||
int maxVolumeSizeGb = NumbersUtil.parseInt(maxVolumeSizeInGbString, 2000);
|
||||
|
||||
_maxVolumeSizeInGb = maxVolumeSizeGb;
|
||||
|
||||
s_logger.info("Snapshot Manager is configured.");
|
||||
|
||||
return true;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user