refactoring createSnapshotPolicy to new API framework...since this is a basic database create just move parameter validation to SnapshotManager and save the snapshot policy in the database

This commit is contained in:
Kris McQueen 2010-08-18 18:24:16 -07:00
parent da03aee028
commit b0668df1b9
6 changed files with 168 additions and 154 deletions

View File

@ -18,40 +18,21 @@
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.BaseCmd.Manager;
import com.cloud.api.Implementation;
import com.cloud.api.Parameter;
import com.cloud.api.ServerApiException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.server.ManagementServer;
import com.cloud.api.response.SnapshotPolicyResponse;
import com.cloud.serializer.SerializerHelper;
import com.cloud.storage.SnapshotPolicyVO;
import com.cloud.storage.StoragePoolVO;
import com.cloud.storage.VolumeVO;
import com.cloud.utils.Pair;
@Implementation(method="createPolicy", manager=Manager.SnapshotManager)
public class CreateSnapshotPolicyCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(CreateSnapshotPolicyCmd.class.getName());
private static final String s_name = "createsnapshotpolicyresponse";
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.DOMAIN_ID, Boolean.FALSE));
s_properties.add(new Pair<Enum, Boolean>(BaseCmd.Properties.INTERVAL_TYPE, Boolean.TRUE));
s_properties.add(new Pair<Enum, Boolean>(BaseCmd.Properties.MAX_SNAPS, Boolean.TRUE));
s_properties.add(new Pair<Enum, Boolean>(BaseCmd.Properties.SCHEDULE, Boolean.TRUE));
s_properties.add(new Pair<Enum, Boolean>(BaseCmd.Properties.TIMEZONE, Boolean.TRUE));
s_properties.add(new Pair<Enum, Boolean>(BaseCmd.Properties.VOLUME_ID, Boolean.TRUE));
}
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
@ -116,74 +97,22 @@ public class CreateSnapshotPolicyCmd extends BaseCmd {
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public String getName() {
return s_name;
}
public List<Pair<Enum, Boolean>> getProperties() {
return s_properties;
}
@Override
public List<Pair<String, Object>> execute(Map<String, Object> params) {
Long userId = (Long)params.get(BaseCmd.Properties.USER_ID.getName());
long volumeId = (Long)params.get(BaseCmd.Properties.VOLUME_ID.getName());
String schedule = (String)params.get(BaseCmd.Properties.SCHEDULE.getName());
String timezone = (String)params.get(BaseCmd.Properties.TIMEZONE.getName());
String intervalType = (String)params.get(BaseCmd.Properties.INTERVAL_TYPE.getName());
//ToDo: make maxSnaps optional. Use system wide max when not specified
int maxSnaps = (Integer)params.get(BaseCmd.Properties.MAX_SNAPS.getName());
ManagementServer managementServer = getManagementServer();
// Verify that a volume exists with the specified volume ID
VolumeVO volume = managementServer.findVolumeById(volumeId);
if (volume == null) {
throw new ServerApiException (BaseCmd.PARAM_ERROR, "Unable to find a volume with id " + volumeId);
}
// If an account was passed in, make sure that it matches the account of the volume
checkAccountPermissions(params, volume.getAccountId(), volume.getDomainId(), "volume", volumeId);
StoragePoolVO storagePoolVO = managementServer.findPoolById(volume.getPoolId());
if (storagePoolVO == null) {
throw new ServerApiException(BaseCmd.PARAM_ERROR, "volumeId: " + volumeId + " does not have a valid storage pool. Is it destroyed?");
}
if (storagePoolVO.isLocal()) {
throw new ServerApiException(BaseCmd.PARAM_ERROR, "Cannot create a snapshot from a volume residing on a local storage pool, poolId: " + volume.getPoolId());
}
Long instanceId = volume.getInstanceId();
if (instanceId != null) {
// It is not detached, but attached to a VM
if (managementServer.findUserVMInstanceById(instanceId) == null) {
// It is not a UserVM but a SystemVM or DomR
throw new ServerApiException(BaseCmd.PARAM_ERROR, "Snapshots of volumes attached to System or router VM are not allowed");
}
}
Long accountId = volume.getAccountId();
// If command is executed via 8096 port, set userId to the id of System account (1)
if (userId == null) {
userId = Long.valueOf(1);
}
SnapshotPolicyVO snapshotPolicy = null;
try {
snapshotPolicy = managementServer.createSnapshotPolicy(accountId, userId, volumeId, schedule, intervalType, maxSnaps, timezone);
} catch (InvalidParameterValueException ex) {
throw new ServerApiException (BaseCmd.VM_INVALID_PARAM_ERROR, ex.getMessage());
}
if (snapshotPolicy == null) {
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to create Snapshot Policy");
}
List<Pair<String, Object>> returnValues = new ArrayList<Pair<String, Object>>();
returnValues.add(new Pair<String, Object>(BaseCmd.Properties.ID.getName(), snapshotPolicy.getId().toString()));
returnValues.add(new Pair<String, Object>(BaseCmd.Properties.VOLUME_ID.getName(), snapshotPolicy.getVolumeId()));
returnValues.add(new Pair<String, Object>(BaseCmd.Properties.SCHEDULE.getName(), snapshotPolicy.getSchedule()));
returnValues.add(new Pair<String, Object>(BaseCmd.Properties.INTERVAL_TYPE.getName(), snapshotPolicy.getInterval()));
returnValues.add(new Pair<String, Object>(BaseCmd.Properties.MAX_SNAPS.getName(), snapshotPolicy.getMaxSnaps()));
return returnValues;
@Override
public String getResponse() {
SnapshotPolicyVO snapshotPolicy = (SnapshotPolicyVO)getResponseObject();
SnapshotPolicyResponse response = new SnapshotPolicyResponse();
response.setId(snapshotPolicy.getId());
response.setIntervalType(snapshotPolicy.getInterval());
response.setMaxSnaps(snapshotPolicy.getMaxSnaps());
response.setSchedule(snapshotPolicy.getSchedule());
response.setVolumeId(snapshotPolicy.getVolumeId());
return SerializerHelper.toSerializedString(response);
}
}

View File

@ -0,0 +1,61 @@
package com.cloud.api.response;
import com.cloud.api.ResponseObject;
import com.cloud.serializer.Param;
public class SnapshotPolicyResponse implements ResponseObject {
@Param(name="id")
private Long id;
@Param(name="volumeid")
private Long volumeId;
@Param(name="schedule")
private String schedule;
@Param(name="intervaltype")
private short intervalType;
@Param(name="maxsnaps")
private int maxSnaps;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getVolumeId() {
return volumeId;
}
public void setVolumeId(Long volumeId) {
this.volumeId = volumeId;
}
public String getSchedule() {
return schedule;
}
public void setSchedule(String schedule) {
this.schedule = schedule;
}
public short getIntervalType() {
return intervalType;
}
public void setIntervalType(short intervalType) {
this.intervalType = intervalType;
}
public int getMaxSnaps() {
return maxSnaps;
}
public void setMaxSnaps(int maxSnaps) {
this.maxSnaps = maxSnaps;
}
}

View File

@ -1877,19 +1877,6 @@ public interface ManagementServer {
StoragePoolVO addPool(Long zoneId, Long podId, Long clusterId, String poolName, String storageUri, String tags, Map<String, String> details) throws ResourceInUseException, URISyntaxException, IllegalArgumentException, UnknownHostException, ResourceAllocationException;
List<? extends StoragePoolVO> searchForStoragePools(Criteria c);
/**
* Creates a policy with specified schedule to create snapshot for a volume . maxSnaps specifies the number of most recent snapshots that are to be retained.
* @param volumeId
* @param schedule MM[:HH][:DD] format. DD is day of week for weekly[1-7] and day of month for monthly
* @param interval hourly/daily/weekly/monthly
* @param maxSnaps If the number of snapshots go beyond maxSnaps the oldest snapshot is deleted
* @param timezone The timezone in which the above time format is specified
* @return
* @throws InvalidParameterValueException
*/
SnapshotPolicyVO createSnapshotPolicy(long userId, long accountId, long volumeId, String schedule, String intervalType,
int maxSnaps, String timezone) throws InvalidParameterValueException;
/**
* List all snapshot policies which are created for the specified volume
* @param volumeId

View File

@ -7734,33 +7734,6 @@ public class ManagementServerImpl implements ManagementServer {
return _jobDao.search(sc, searchFilter);
}
@Override
public SnapshotPolicyVO createSnapshotPolicy(long userId, long accountId, long volumeId, String schedule, String intervalType, int maxSnaps, String timeZoneStr) throws InvalidParameterValueException {
IntervalType type = DateUtil.IntervalType.getIntervalType(intervalType);
if(type == null){
throw new InvalidParameterValueException("Unsupported interval type " + intervalType);
}
TimeZone timeZone = TimeZone.getTimeZone(timeZoneStr);
String timezoneId = timeZone.getID();
if (!timezoneId.equals(timeZoneStr)) {
s_logger.warn("Using timezone: " + timezoneId + " for running this snapshot policy as an equivalent of " + timeZoneStr);
}
try {
DateUtil.getNextRunTime(type, schedule, timezoneId, null);
} catch (Exception e){
throw new InvalidParameterValueException("Invalid schedule: "+ schedule +" for interval type: " + intervalType);
}
int intervalMaxSnaps = type.getMax();
if(maxSnaps > intervalMaxSnaps){
throw new InvalidParameterValueException("maxSnaps exceeds limit: "+ intervalMaxSnaps +" for interval type: " + intervalType);
}
return _snapMgr.createPolicy(userId, accountId, volumeId, schedule, (short)type.ordinal() , maxSnaps, timezoneId);
}
@Override
public SnapshotPolicyVO findSnapshotPolicyById(Long policyId) {
return _snapshotPolicyDao.findById(policyId);

View File

@ -19,13 +19,13 @@ package com.cloud.storage.snapshot;
import java.util.List;
import com.cloud.api.commands.CreateSnapshotPolicyCmd;
import com.cloud.exception.InternalErrorException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.storage.SnapshotPolicyVO;
import com.cloud.storage.SnapshotScheduleVO;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.VolumeVO;
import com.cloud.utils.component.Manager;
import com.cloud.utils.db.Filter;
@ -94,16 +94,14 @@ public interface SnapshotManager extends Manager {
* This will be used for manual snapshots too.
*/
boolean deleteSnapshot(long userId, long snapshotId, long policyId);
/**
* Creates a policy with specified schedule. maxSnaps specifies the number of most recent snapshots that are to be retained.
* If the number of snapshots go beyond maxSnaps the oldest snapshot is deleted
* @param volumeId
* @param userId
* @param timeZone The timezone in which the 'schedule' string is specified
* @param cmd the command that
* @return the newly created snapshot policy if success, null otherwise
*/
SnapshotPolicyVO createPolicy(long userId, long accountId, long volumeId, String schedule, short interval, int maxSnaps, String timezone);
SnapshotPolicyVO createPolicy(CreateSnapshotPolicyCmd cmd) throws InvalidParameterValueException;
/**
* Deletes snapshot scheduling policy. Delete will fail if this policy is assigned to one or more volumes

View File

@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import javax.ejb.Local;
import javax.naming.ConfigurationException;
@ -40,6 +41,7 @@ import com.cloud.agent.api.ValidateSnapshotCommand;
import com.cloud.agent.manager.AgentManager;
import com.cloud.api.BaseCmd;
import com.cloud.api.commands.CreateSnapshotCmd;
import com.cloud.api.commands.CreateSnapshotPolicyCmd;
import com.cloud.api.commands.CreateVolumeCmd;
import com.cloud.async.AsyncJobExecutor;
import com.cloud.async.AsyncJobManager;
@ -68,6 +70,7 @@ import com.cloud.storage.SnapshotScheduleVO;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePoolVO;
import com.cloud.storage.VMTemplateStoragePoolVO;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Volume.VolumeType;
@ -84,9 +87,12 @@ import com.cloud.storage.dao.VMTemplatePoolDao;
import com.cloud.storage.dao.VolumeDao;
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;
import com.cloud.user.dao.UserDao;
import com.cloud.utils.DateUtil;
import com.cloud.utils.DateUtil.IntervalType;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.component.ComponentLocator;
import com.cloud.utils.component.Inject;
@ -134,7 +140,6 @@ public class SnapshotManagerImpl implements SnapshotManager {
protected SearchBuilder<SnapshotVO> PolicySnapshotSearch;
protected SearchBuilder<SnapshotPolicyVO> PoliciesForSnapSearch;
private String _hypervisorType;
private final boolean _shouldBeSnapshotCapable = true; // all methods here should be snapshot capable.
@Override @DB
@ -1071,9 +1076,66 @@ public class SnapshotManagerImpl implements SnapshotManager {
@Override
@DB
public SnapshotPolicyVO createPolicy(long userId, long accountId, long volumeId, String schedule, short interval, int maxSnaps, String timezone) {
public SnapshotPolicyVO createPolicy(CreateSnapshotPolicyCmd cmd) throws InvalidParameterValueException {
Long volumeId = cmd.getVolumeId();
VolumeVO volume = _volsDao.findById(cmd.getVolumeId());
if (volume == null) {
throw new InvalidParameterValueException("Failed to create snapshot policy, unable to find a volume with id " + volumeId);
}
// TODO: implement
// If an account was passed in, make sure that it matches the account of the volume
// checkAccountPermissions(params, volume.getAccountId(), volume.getDomainId(), "volume", volumeId);
StoragePoolVO storagePoolVO = _storagePoolDao.findById(volume.getPoolId());
if (storagePoolVO == null) {
throw new InvalidParameterValueException("Failed to create snapshot policy, volumeId: " + volumeId + " does not have a valid storage pool. Is it destroyed?");
}
if (storagePoolVO.isLocal()) {
throw new InvalidParameterValueException("Failed to create snapshot policy, cannot create a snapshot from a volume residing on a local storage pool, poolId: " + volume.getPoolId());
}
Long instanceId = volume.getInstanceId();
if (instanceId != null) {
// It is not detached, but attached to a VM
if (_vmDao.findById(instanceId) == null) {
// It is not a UserVM but a SystemVM or DomR
throw new InvalidParameterValueException("Failed to create snapshot policy, snapshots of volumes attached to System or router VM are not allowed");
}
}
Long accountId = volume.getAccountId();
Long userId = UserContext.current().getUserId();
// If command is executed via 8096 port, set userId to the id of System account (1)
if (userId == null) {
userId = User.UID_SYSTEM;
}
IntervalType type = DateUtil.IntervalType.getIntervalType(cmd.getIntervalType());
if (type == null) {
throw new InvalidParameterValueException("Unsupported interval type " + cmd.getIntervalType());
}
TimeZone timeZone = TimeZone.getTimeZone(cmd.getTimezone());
String timezoneId = timeZone.getID();
if (!timezoneId.equals(cmd.getTimezone())) {
s_logger.warn("Using timezone: " + timezoneId + " for running this snapshot policy as an equivalent of " + cmd.getTimezone());
}
try {
DateUtil.getNextRunTime(type, cmd.getSchedule(), timezoneId, null);
} catch (Exception e){
throw new InvalidParameterValueException("Invalid schedule: "+ cmd.getSchedule() +" for interval type: " + cmd.getIntervalType());
}
int intervalMaxSnaps = type.getMax();
if (cmd.getMaxSnaps() > intervalMaxSnaps) {
throw new InvalidParameterValueException("maxSnaps exceeds limit: " + intervalMaxSnaps + " for interval type: " + cmd.getIntervalType());
}
Long policyId = null;
SnapshotPolicyVO policy = getPolicyForVolumeByInterval(volumeId, (interval));
SnapshotPolicyVO policy = getPolicyForVolumeByInterval(volumeId, (short)type.ordinal());
Transaction txn = Transaction.currentTxn();
txn.start();
@ -1082,30 +1144,34 @@ public class SnapshotManagerImpl implements SnapshotManager {
event.setAccountId(accountId);
event.setUserId(userId);
if( policy != null){
s_logger.debug("Policy for specified interval already exists. Updating policy to new schedule");
if (policy != null) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Policy for specified interval already exists. Updating policy to new schedule");
}
policyId = policy.getId();
// By default, assume failure.
event.setType(EventTypes.EVENT_SNAPSHOT_POLICY_UPDATE);
event.setDescription("Failed to update schedule for Snapshot policy with id: "+policyId);
event.setDescription("Failed to update schedule for Snapshot policy with id: " + policyId);
event.setLevel(EventVO.LEVEL_ERROR);
// Check if there are any recurring snapshots being currently executed. Race condition.
SnapshotScheduleVO snapshotSchedule = _snapshotScheduleDao.getCurrentSchedule(volumeId, policyId, true);
if (snapshotSchedule != null) {
Date scheduledTimestamp = snapshotSchedule.getScheduledTimestamp();
String dateDisplay = DateUtil.displayDateInTimezone(DateUtil.GMT_TIMEZONE, scheduledTimestamp);
s_logger.debug("Cannot update the policy now. Wait until the current snapshot scheduled at " + dateDisplay + " finishes");
if (s_logger.isDebugEnabled()) {
s_logger.debug("Cannot update the policy now. Wait until the current snapshot scheduled at " + dateDisplay + " finishes");
}
policyId = null;
policy = null;
}
else {
_snapSchedMgr.removeSchedule(volumeId, policyId);
policy.setSchedule(schedule);
policy.setTimezone(timezone);
policy.setMaxSnaps(maxSnaps);
policy.setSchedule(cmd.getSchedule());
policy.setTimezone(cmd.getTimezone());
policy.setMaxSnaps(cmd.getMaxSnaps());
policy.setActive(true);
if(_snapshotPolicyDao.update(policy.getId(), policy)){
@ -1114,7 +1180,7 @@ public class SnapshotManagerImpl implements SnapshotManager {
}
}
} else {
policy = new SnapshotPolicyVO(volumeId, schedule, timezone, interval, maxSnaps);
policy = new SnapshotPolicyVO(volumeId, cmd.getSchedule(), cmd.getTimezone(), (short)type.ordinal(), cmd.getMaxSnaps());
policy = _snapshotPolicyDao.persist(policy);
policyId = policy.getId();
event.setType(EventTypes.EVENT_SNAPSHOT_POLICY_CREATE);
@ -1126,10 +1192,12 @@ public class SnapshotManagerImpl implements SnapshotManager {
_snapSchedMgr.scheduleNextSnapshotJob(policy);
}
else {
s_logger.debug("Failed to update schedule for Snapshot policy with id: " + policyId);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Failed to update schedule for Snapshot policy with id: " + policyId);
}
}
txn.commit();
return policy;
}
@ -1295,8 +1363,6 @@ public class SnapshotManagerImpl implements SnapshotManager {
throw new ConfigurationException("Unable to get the configuration dao.");
}
_hypervisorType = configDao.getValue("hypervisor.type");
DateUtil.IntervalType.HOURLY.setMax(NumbersUtil.parseInt(configDao.getValue("snapshot.max.hourly"), HOURLYMAX));
DateUtil.IntervalType.DAILY.setMax(NumbersUtil.parseInt(configDao.getValue("snapshot.max.daily"), DAILYMAX));
DateUtil.IntervalType.WEEKLY.setMax(NumbersUtil.parseInt(configDao.getValue("snapshot.max.weekly"), WEEKLYMAX));