diff --git a/api/src/com/cloud/storage/Snapshot.java b/api/src/com/cloud/storage/Snapshot.java index 7a0cd896842..453fa57abbc 100644 --- a/api/src/com/cloud/storage/Snapshot.java +++ b/api/src/com/cloud/storage/Snapshot.java @@ -26,7 +26,20 @@ public interface Snapshot { public enum Type { MANUAL, RECURRING, - TEMPLATE; + TEMPLATE, + HOURLY, + DAILY, + WEEKLY, + MONTHLY; + private int max = 8; + + public void setMax(int max) { + this.max = max; + } + + public int getMax() { + return max; + } public String toString() { return this.name(); @@ -52,7 +65,7 @@ public interface Snapshot { } } - public static final long MANUAL_POLICY_ID = 1L; + public static final long MANUAL_POLICY_ID = 0L; Long getId(); long getAccountId(); @@ -60,7 +73,10 @@ public interface Snapshot { String getPath(); String getName(); Date getCreated(); - short getSnapshotType(); + Type getType(); Status getStatus(); HypervisorType getHypervisorType(); + boolean isRecursive(); + short getsnapshotType(); + } diff --git a/api/src/com/cloud/vm/DiskProfile.java b/api/src/com/cloud/vm/DiskProfile.java index d251e71521d..321d732bf0b 100644 --- a/api/src/com/cloud/vm/DiskProfile.java +++ b/api/src/com/cloud/vm/DiskProfile.java @@ -56,7 +56,7 @@ public class DiskProfile { } public DiskProfile(Volume vol, DiskOffering offering, HypervisorType hyperType) { - this(vol.getId(), vol.getVolumeType(), vol.getName(), offering.getId(), vol.getSize(), offering.getTagsArray(), offering.getUseLocalStorage(), offering.getUseLocalStorage(), vol.getSize()); + this(vol.getId(), vol.getVolumeType(), vol.getName(), offering.getId(), vol.getSize(), offering.getTagsArray(), offering.getUseLocalStorage(), offering.isCustomized(), null); this.hyperType = hyperType; } diff --git a/core/src/com/cloud/storage/SnapshotPolicyVO.java b/core/src/com/cloud/storage/SnapshotPolicyVO.java index a7c226ddbb2..bd1688a5958 100644 --- a/core/src/com/cloud/storage/SnapshotPolicyVO.java +++ b/core/src/com/cloud/storage/SnapshotPolicyVO.java @@ -26,6 +26,7 @@ import javax.persistence.Id; import javax.persistence.Table; import com.cloud.storage.snapshot.SnapshotPolicy; +import com.cloud.utils.DateUtil.IntervalType; @Entity @Table(name="snapshot_policy") @@ -56,11 +57,11 @@ public class SnapshotPolicyVO implements SnapshotPolicy { public SnapshotPolicyVO() { } - public SnapshotPolicyVO(long volumeId, String schedule, String timezone, short interval, int maxSnaps) { + public SnapshotPolicyVO(long volumeId, String schedule, String timezone, IntervalType intvType, int maxSnaps) { this.volumeId = volumeId; this.schedule = schedule; this.timezone = timezone; - this.interval = interval; + this.interval = (short)intvType.ordinal(); this.maxSnaps = maxSnaps; this.active = true; } diff --git a/core/src/com/cloud/storage/SnapshotScheduleVO.java b/core/src/com/cloud/storage/SnapshotScheduleVO.java index 8dfc538f2c2..0fdedceade1 100644 --- a/core/src/com/cloud/storage/SnapshotScheduleVO.java +++ b/core/src/com/cloud/storage/SnapshotScheduleVO.java @@ -98,7 +98,7 @@ public class SnapshotScheduleVO implements SnapshotSchedule { return asyncJobId; } - public void setAsyncJobId(long asyncJobId) { + public void setAsyncJobId(Long asyncJobId) { this.asyncJobId = asyncJobId; } diff --git a/core/src/com/cloud/storage/SnapshotVO.java b/core/src/com/cloud/storage/SnapshotVO.java index 250fd8fcc96..171f7496e29 100644 --- a/core/src/com/cloud/storage/SnapshotVO.java +++ b/core/src/com/cloud/storage/SnapshotVO.java @@ -19,7 +19,6 @@ package com.cloud.storage; import java.util.Date; -import java.util.List; import javax.persistence.Column; import javax.persistence.Entity; @@ -29,7 +28,6 @@ import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; -import javax.persistence.TableGenerator; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.utils.db.GenericDao; @@ -42,10 +40,16 @@ public class SnapshotVO implements Snapshot { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="id") - private long id = -1; + private long id = -1; + + @Column(name="data_center_id") + long dataCenterId; @Column(name="account_id") - long accountId; + long accountId; + + @Column(name="domain_id") + long domainId; @Column(name="volume_id") Long volumeId; @@ -67,8 +71,11 @@ public class SnapshotVO implements Snapshot { short snapshotType; @Column(name="type_description") - String typeDescription; - + String typeDescription; + + @Column(name="size") + long size; + @Column(name=GenericDao.CREATED_COLUMN) Date created; @@ -87,13 +94,16 @@ public class SnapshotVO implements Snapshot { public SnapshotVO() { } - public SnapshotVO(long accountId, Long volumeId, String path, String name, short snapshotType, String typeDescription, HypervisorType hypervisorType) { - this.accountId = accountId; + public SnapshotVO(long dcId, long accountId, long domainId, Long volumeId, String path, String name, short snapshotType, String typeDescription, long size, HypervisorType hypervisorType) { + this.dataCenterId = dcId; + this.accountId = accountId; + this.domainId = domainId; this.volumeId = volumeId; this.path = path; this.name = name; this.snapshotType = snapshotType; - this.typeDescription = typeDescription; + this.typeDescription = typeDescription; + this.size = size; this.status = Status.Creating; this.prevSnapshotId = 0; this.hypervisorType = hypervisorType; @@ -104,11 +114,19 @@ public class SnapshotVO implements Snapshot { return id; } + public long getDataCenterId() { + return dataCenterId; + } + @Override public long getAccountId() { return accountId; } + public long getDomainId() { + return domainId; + } + @Override public long getVolumeId() { return volumeId; @@ -131,12 +149,19 @@ public class SnapshotVO implements Snapshot { public String getName() { return name; } - - @Override - public short getSnapshotType() { - return snapshotType; + @Override + public short getsnapshotType() { + return snapshotType; } + @Override + public Type getType() { + if (snapshotType < 0 || snapshotType >= Type.values().length) { + return null; + } + return Type.values()[snapshotType]; + } + @Override public HypervisorType getHypervisorType() { return hypervisorType; @@ -144,8 +169,20 @@ public class SnapshotVO implements Snapshot { public void setSnapshotType(short snapshotType) { this.snapshotType = snapshotType; + } + + @Override + public boolean isRecursive(){ + if ( snapshotType >= Type.DAILY.ordinal() && snapshotType <= Type.MONTHLY.ordinal() ) { + return true; + } + return false; } + public long getSize() { + return size; + } + public String getTypeDescription() { return typeDescription; } @@ -185,25 +222,14 @@ public class SnapshotVO implements Snapshot { public void setPrevSnapshotId(long prevSnapshotId){ this.prevSnapshotId = prevSnapshotId; } - - public static Type getSnapshotType(Long policyId) { - if (policyId.equals(MANUAL_POLICY_ID)) { - return Type.MANUAL; - } else { - return Type.RECURRING; - } - } - + public static Type getSnapshotType(String snapshotType) { - if (Type.MANUAL.equals(snapshotType)) { - return Type.MANUAL; - } - if (Type.RECURRING.equals(snapshotType)) { - return Type.RECURRING; - } - if (Type.TEMPLATE.equals(snapshotType)) { - return Type.TEMPLATE; + for ( Type type : Type.values()) { + if ( type.equals(snapshotType)) { + return type; + } } return null; - } + } + } diff --git a/core/src/com/cloud/storage/VolumeVO.java b/core/src/com/cloud/storage/VolumeVO.java index 21ffc5987c7..267f2ddbaa4 100755 --- a/core/src/com/cloud/storage/VolumeVO.java +++ b/core/src/com/cloud/storage/VolumeVO.java @@ -428,54 +428,6 @@ public class VolumeVO implements Volume { this.updated = updated; } - public Lun getLun() { - return new Lun(hostip, iscsiName); - } - - public class Lun { - private final String ip; - private String iqn; - private String lun; - - protected Lun(String ip, String iscsiName) { - this.ip = ip; - String[] str = iscsiName.split(":lu:"); - if (str != null && str.length == 2) { - iqn = str[0]; - lun = str[1]; - } else { - iqn = null; - lun = null; - } - } - - public Lun(String ip, String iqn, String lun) { - this.ip = ip; - this.iqn = iqn; - this.lun = lun; - } - - public String getIp() { - return ip; - } - - public String getIqn() { - return iqn; - } - - public String getLun() { - return lun; - } - - public boolean isIscsi() { - return lun != null; - } - - protected String getIscsiName() { - return iqn + ":lu:" + lun; - } - } - @Override public String toString() { return new StringBuilder("Vol[").append(id).append("|vm=").append(instanceId).append("|").append(volumeType).append("]").toString(); diff --git a/core/src/com/cloud/storage/snapshot/SnapshotSchedule.java b/core/src/com/cloud/storage/snapshot/SnapshotSchedule.java index 13a4148e716..f83a2aa006f 100644 --- a/core/src/com/cloud/storage/snapshot/SnapshotSchedule.java +++ b/core/src/com/cloud/storage/snapshot/SnapshotSchedule.java @@ -37,7 +37,7 @@ public interface SnapshotSchedule { Long getAsyncJobId(); - void setAsyncJobId(long asyncJobId); + void setAsyncJobId(Long asyncJobId); Long getSnapshotId(); diff --git a/server/src/com/cloud/agent/AgentManager.java b/server/src/com/cloud/agent/AgentManager.java index 5c750de25f0..c7c2fe9cd5c 100755 --- a/server/src/com/cloud/agent/AgentManager.java +++ b/server/src/com/cloud/agent/AgentManager.java @@ -37,6 +37,7 @@ import com.cloud.host.HostStats; import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.Status.Event; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.offering.ServiceOffering; import com.cloud.resource.ServerResource; import com.cloud.service.ServiceOfferingVO; @@ -226,4 +227,6 @@ public interface AgentManager extends Manager { boolean isHostNativeHAEnabled(long hostId); + Answer sendTo(Long dcId, HypervisorType type, Command cmd); + } diff --git a/server/src/com/cloud/agent/manager/AgentManagerImpl.java b/server/src/com/cloud/agent/manager/AgentManagerImpl.java index 0a18d6e44c0..cc0004b2a97 100755 --- a/server/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/server/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -108,6 +108,7 @@ import com.cloud.exception.DiscoveryException; import com.cloud.exception.InsufficientServerCapacityException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.OperationTimedoutException; +import com.cloud.exception.StorageUnavailableException; import com.cloud.exception.UnsupportedVersionException; import com.cloud.ha.HighAvailabilityManager; import com.cloud.ha.HighAvailabilityManager.WorkType; @@ -138,9 +139,11 @@ import com.cloud.service.ServiceOfferingVO; import com.cloud.storage.GuestOSCategoryVO; import com.cloud.storage.Storage; import com.cloud.storage.StorageManager; +import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolVO; import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.Volume; import com.cloud.storage.dao.GuestOSCategoryDao; import com.cloud.storage.dao.StoragePoolDao; import com.cloud.storage.dao.StoragePoolHostDao; @@ -961,6 +964,30 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, } } + @Override + public Answer sendTo(Long dcId, HypervisorType type, Command cmd) { + List clusters = _clusterDao.listByDcHyType(dcId, type.toString()); + int retry = 0; + for( ClusterVO cluster : clusters ) { + List hosts = _hostDao.listBy(Host.Type.Routing, cluster.getId(), null, dcId); + for ( HostVO host : hosts ) { + retry++; + if ( retry > _retry ) { + return null; + } + Answer answer = null; + try { + answer = easySend( host.getId(), cmd); + } catch (Exception e ) { + } + if ( answer != null ) { + return answer; + } + } + } + return null; + } + @Override @DB public boolean deleteHost(long hostId) { diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index 26e80fbe008..d9cac8dc3ca 100755 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -258,25 +258,8 @@ public class ApiDBUtils { } public static String getSnapshotIntervalTypes(long snapshotId) { - String intervalTypes = ""; - SnapshotVO snapshot = _snapshotDao.findById(snapshotId); - if (snapshot.getSnapshotType() == Snapshot.Type.MANUAL.ordinal()) { - return "MANUAL"; - } - - List policies = _snapMgr.listPoliciesforVolume(snapshot.getVolumeId()); - for (SnapshotPolicyVO policy : policies) { - if (!intervalTypes.isEmpty()) { - intervalTypes += ","; - } - if (policy.getId() == Snapshot.MANUAL_POLICY_ID) { - intervalTypes += "MANUAL"; - } else { - intervalTypes += DateUtil.getIntervalType(policy.getInterval()).toString(); - } - } - return intervalTypes; + return snapshot.getType().name(); } public static String getStoragePoolTags(long poolId) { diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 3fc0fda1d7e..4597d5eeb15 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -444,7 +444,7 @@ public class ApiResponseHelper implements ResponseGenerator { } VolumeVO volume = findVolumeById(snapshot.getVolumeId()); - String snapshotTypeStr = Type.values()[snapshot.getSnapshotType()].name(); + String snapshotTypeStr = snapshot.getType().name(); snapshotResponse.setSnapshotType(snapshotTypeStr); snapshotResponse.setVolumeId(snapshot.getVolumeId()); if( volume != null ) { diff --git a/server/src/com/cloud/dc/dao/ClusterDao.java b/server/src/com/cloud/dc/dao/ClusterDao.java index f0689608263..3716b48341b 100644 --- a/server/src/com/cloud/dc/dao/ClusterDao.java +++ b/server/src/com/cloud/dc/dao/ClusterDao.java @@ -29,4 +29,5 @@ public interface ClusterDao extends GenericDao { List listByHyTypeWithoutGuid(String hyType); List listByZoneId(long zoneId); List getAvailableHypervisorInZone(long zoneId); + List listByDcHyType(long dcId, String hyType); } diff --git a/server/src/com/cloud/dc/dao/ClusterDaoImpl.java b/server/src/com/cloud/dc/dao/ClusterDaoImpl.java index c57b15ee3df..ab9837cf181 100644 --- a/server/src/com/cloud/dc/dao/ClusterDaoImpl.java +++ b/server/src/com/cloud/dc/dao/ClusterDaoImpl.java @@ -35,6 +35,7 @@ public class ClusterDaoImpl extends GenericDaoBase implements C protected final SearchBuilder HyTypeWithoutGuidSearch; protected final SearchBuilder AvailHyperSearch; protected final SearchBuilder ZoneSearch; + protected final SearchBuilder ZoneHyTypeSearch; protected ClusterDaoImpl() { super(); @@ -43,6 +44,11 @@ public class ClusterDaoImpl extends GenericDaoBase implements C HyTypeWithoutGuidSearch.and("guid", HyTypeWithoutGuidSearch.entity().getGuid(), SearchCriteria.Op.NULL); HyTypeWithoutGuidSearch.done(); + ZoneHyTypeSearch = createSearchBuilder(); + ZoneHyTypeSearch.and("hypervisorType", ZoneHyTypeSearch.entity().getHypervisorType(), SearchCriteria.Op.EQ); + ZoneHyTypeSearch.and("dataCenterId", ZoneHyTypeSearch.entity().getPodId(), SearchCriteria.Op.EQ); + ZoneHyTypeSearch.done(); + PodSearch = createSearchBuilder(); PodSearch.and("pod", PodSearch.entity().getPodId(), SearchCriteria.Op.EQ); PodSearch.and("name", PodSearch.entity().getName(), SearchCriteria.Op.EQ); @@ -90,6 +96,14 @@ public class ClusterDaoImpl extends GenericDaoBase implements C return listBy(sc); } + @Override + public List listByDcHyType(long dcId, String hyType) { + SearchCriteria sc = ZoneHyTypeSearch.create(); + sc.setParameters("dataCenterId", dcId); + sc.setParameters("hypervisorType", hyType); + return listBy(sc); + } + @Override public List getAvailableHypervisorInZone(long zoneId) { SearchCriteria sc = AvailHyperSearch.create(); diff --git a/server/src/com/cloud/host/dao/HostDaoImpl.java b/server/src/com/cloud/host/dao/HostDaoImpl.java index 93e94f99f88..6cfd466d261 100644 --- a/server/src/com/cloud/host/dao/HostDaoImpl.java +++ b/server/src/com/cloud/host/dao/HostDaoImpl.java @@ -299,15 +299,17 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao @Override public List listBy(Host.Type type, Long clusterId, Long podId, long dcId) { - SearchCriteria sc = TypePodDcStatusSearch.create(); - sc.setParameters("type", type.toString()); - if (podId != null) { - sc.setParameters("pod", podId); + SearchCriteria sc = TypePodDcStatusSearch.create(); + if ( type != null ) { + sc.setParameters("type", type.toString()); } if (clusterId != null) { sc.setParameters("cluster", clusterId); - } - sc.setParameters("dc", dcId); + } + if (podId != null ) { + sc.setParameters("pod", podId); + } + sc.setParameters("dc", dcId); sc.setParameters("status", Status.Up.toString()); return listBy(sc); @@ -333,7 +335,7 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao sc.setParameters("cluster", clusterId); return listBy(sc); - } + } @Override public List listBy(Host.Type type, long dcId) { diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java index f47d33be2bf..9a86f19d47b 100644 --- a/server/src/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/com/cloud/server/ConfigurationServerImpl.java @@ -184,10 +184,6 @@ public class ConfigurationServerImpl implements ConfigurationServer { createDiskOffering(DomainVO.ROOT_DOMAIN, "Large", "Large Disk, 100 GB", 100, null); //_configMgr.createDiskOffering(User.UID_SYSTEM, DomainVO.ROOT_DOMAIN, "Private", "Private Disk", 0, null); - //Add default manual snapshot policy - SnapshotPolicyVO snapPolicy = new SnapshotPolicyVO(0L, "00", "GMT", (short)4, 0); - _snapPolicyDao.persist(snapPolicy); - // Save the mount parent to the configuration table String mountParent = getMountParent(); if (mountParent != null) { diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 25fa6a5da29..b9815560e67 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -410,7 +410,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag } @DB - protected Pair createVolumeFromSnapshot(VolumeVO volume, SnapshotVO snapshot, long virtualsize) { + protected Pair createVolumeFromSnapshot(VolumeVO volume, SnapshotVO snapshot) { VolumeVO createdVolume = null; Long volumeId = volume.getId(); @@ -466,7 +466,6 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag } } - s_logger.warn("Unable to create volume on pool " + pool.getName() + ", reason: " + details); } @@ -515,18 +514,20 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag // By default, assume failure. VolumeVO createdVolume = null; SnapshotVO snapshot = _snapshotDao.findById(snapshotId); // Precondition: snapshot is not null and not removed. - Long origVolumeId = snapshot.getVolumeId(); - VolumeVO originalVolume = _volsDao.findById(origVolumeId); // NOTE: Original volume could be destroyed and removed. - Pair volumeDetails = createVolumeFromSnapshot(volume, snapshot, originalVolume.getSize()); + Pair volumeDetails = createVolumeFromSnapshot(volume, snapshot); createdVolume = volumeDetails.first(); Transaction txn = Transaction.currentTxn(); txn.start(); +<<<<<<< Updated upstream // Create an event Long templateId = originalVolume.getTemplateId(); ; Long diskOfferingId = originalVolume.getDiskOfferingId(); +======= + Long diskOfferingId = volume.getDiskOfferingId(); +>>>>>>> Stashed changes if (createdVolume.getPath() != null) { Long offeringId = null; @@ -537,9 +538,15 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag } } +<<<<<<< Updated upstream // UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), // volume.getId(), volume.getName(), offeringId, templateId, createdVolume.getSize()); // _usageEventDao.persist(usageEvent); +======= + UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), + volume.getId(), volume.getName(), offeringId, null, createdVolume.getSize()); + _usageEventDao.persist(usageEvent); +>>>>>>> Stashed changes } txn.commit(); return createdVolume; @@ -809,17 +816,15 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag Long vmId = volume.getInstanceId(); if (vmId != null) { UserVm vm = _userVmDao.findById(vmId); - if (vm == null) { - return false; + return true; } - - if (!vm.getState().equals(State.Stopped)) { - return false; + State state = vm.getState(); + if (state.equals(State.Stopped) || state.equals(State.Destroyed) ) { + return true; } } - - return true; + return false; } @Override @@ -1449,17 +1454,28 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag } } else { Long snapshotId = cmd.getSnapshotId(); +<<<<<<< Updated upstream Snapshot snapshotCheck = _snapshotDao.findById(snapshotId); +======= + SnapshotVO snapshotCheck = _snapshotDao.findById(snapshotId); + diskOfferingId = cmd.getDiskOfferingId(); +>>>>>>> Stashed changes if (snapshotCheck == null) { throw new InvalidParameterValueException("unable to find a snapshot with id " + snapshotId); } +<<<<<<< Updated upstream VolumeVO vol = _volsDao.findByIdIncludingRemoved(snapshotCheck.getVolumeId()); zoneId = vol.getDataCenterId(); size = vol.getSize(); //we maintain size from org vol ; disk offering is used for tags purposes diskOfferingId = vol.getDiskOfferingId(); +======= + zoneId = snapshotCheck.getDataCenterId(); + size = snapshotCheck.getSize(); //we maintain size from org vol ; disk offering is used for tags purposes + +>>>>>>> Stashed changes if (account != null) { if (isAdmin(account.getType())) { Account snapshotOwner = _accountDao.findById(snapshotCheck.getAccountId()); @@ -1531,7 +1547,6 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag if (cmd.getSnapshotId() != null) { return createVolumeFromSnapshot(volume, cmd.getSnapshotId()); } else { - DiskOfferingVO diskOffering = _diskOfferingDao.findById(cmd.getDiskOfferingId()); _accountMgr.incrementResourceCount(volume.getAccountId(), ResourceType.volume); volume.setStatus(AsyncInstanceCreateStatus.Created); _volsDao.update(volume.getId(), volume); diff --git a/server/src/com/cloud/storage/dao/SnapshotDao.java b/server/src/com/cloud/storage/dao/SnapshotDao.java index 9e4f8aef124..edac0b0c6af 100644 --- a/server/src/com/cloud/storage/dao/SnapshotDao.java +++ b/server/src/com/cloud/storage/dao/SnapshotDao.java @@ -21,6 +21,7 @@ package com.cloud.storage.dao; import java.util.List; import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Snapshot.Type; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDao; @@ -29,7 +30,7 @@ public interface SnapshotDao extends GenericDao { List listByVolumeId(Filter filter, long volumeId); SnapshotVO findNextSnapshot(long parentSnapId); long getLastSnapshot(long volumeId, long snapId); - List listByVolumeIdType(long volumeId, String type); + List listByVolumeIdType(long volumeId, Type type); List listByVolumeIdIncludingRemoved(long volumeId); List listByBackupUuid(long volumeId, String backupUuid); diff --git a/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java b/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java index 9757bc43a17..f70c75a768d 100644 --- a/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java +++ b/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java @@ -27,6 +27,7 @@ import javax.ejb.Local; import org.apache.log4j.Logger; import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Snapshot.Type; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; @@ -58,7 +59,7 @@ public class SnapshotDaoImpl extends GenericDaoBase implements } @Override - public List listByVolumeIdType(long volumeId, String type ) { + public List listByVolumeIdType(long volumeId, Type type ) { return listByVolumeIdType(null, volumeId, type); } @@ -81,10 +82,10 @@ public class SnapshotDaoImpl extends GenericDaoBase implements return listIncludingRemovedBy(sc, null); } - public List listByVolumeIdType(Filter filter, long volumeId, String type ) { + public List listByVolumeIdType(Filter filter, long volumeId, Type type ) { SearchCriteria sc = VolumeIdTypeSearch.create(); sc.setParameters("volumeId", volumeId); - sc.setParameters("type", type); + sc.setParameters("type", type.ordinal()); return listBy(sc, filter); } @@ -95,7 +96,7 @@ public class SnapshotDaoImpl extends GenericDaoBase implements VolumeIdTypeSearch = createSearchBuilder(); VolumeIdTypeSearch.and("volumeId", VolumeIdTypeSearch.entity().getVolumeId(), SearchCriteria.Op.EQ); - VolumeIdTypeSearch.and("type", VolumeIdTypeSearch.entity().getTypeDescription(), SearchCriteria.Op.EQ); + VolumeIdTypeSearch.and("type", VolumeIdTypeSearch.entity().getsnapshotType(), SearchCriteria.Op.EQ); VolumeIdTypeSearch.done(); ParentIdSearch = createSearchBuilder(); diff --git a/server/src/com/cloud/storage/dao/SnapshotPolicyDao.java b/server/src/com/cloud/storage/dao/SnapshotPolicyDao.java index 3b7a32d8c35..512bd2e3cf0 100644 --- a/server/src/com/cloud/storage/dao/SnapshotPolicyDao.java +++ b/server/src/com/cloud/storage/dao/SnapshotPolicyDao.java @@ -21,6 +21,7 @@ package com.cloud.storage.dao; import java.util.List; import com.cloud.storage.SnapshotPolicyVO; +import com.cloud.utils.DateUtil.IntervalType; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDao; @@ -30,7 +31,7 @@ import com.cloud.utils.db.GenericDao; public interface SnapshotPolicyDao extends GenericDao { List listByVolumeId(long volumeId); List listByVolumeId(long volumeId, Filter filter); - SnapshotPolicyVO findOneByVolumeInterval(long volumeId, short interval); + SnapshotPolicyVO findOneByVolumeInterval(long volumeId, IntervalType intvType); List listActivePolicies(); SnapshotPolicyVO findOneByVolume(long volumeId); } diff --git a/server/src/com/cloud/storage/dao/SnapshotPolicyDaoImpl.java b/server/src/com/cloud/storage/dao/SnapshotPolicyDaoImpl.java index a4dbb5fd7af..bf8a4aae195 100644 --- a/server/src/com/cloud/storage/dao/SnapshotPolicyDaoImpl.java +++ b/server/src/com/cloud/storage/dao/SnapshotPolicyDaoImpl.java @@ -24,6 +24,7 @@ import java.util.List; import javax.ejb.Local; import com.cloud.storage.SnapshotPolicyVO; +import com.cloud.utils.DateUtil.IntervalType; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; @@ -36,11 +37,11 @@ public class SnapshotPolicyDaoImpl extends GenericDaoBase ActivePolicySearch; @Override - public SnapshotPolicyVO findOneByVolumeInterval(long volumeId, short interval) { + public SnapshotPolicyVO findOneByVolumeInterval(long volumeId, IntervalType intvType) { SearchCriteria sc = VolumeIdIntervalSearch.create(); sc.setParameters("volumeId", volumeId); - sc.setParameters("interval", interval); - return findOneIncludingRemovedBy(sc); + sc.setParameters("interval", intvType.ordinal()); + return findOneBy(sc); } @Override diff --git a/server/src/com/cloud/storage/dao/SnapshotScheduleDao.java b/server/src/com/cloud/storage/dao/SnapshotScheduleDao.java index 85d82dfa45d..86019215959 100644 --- a/server/src/com/cloud/storage/dao/SnapshotScheduleDao.java +++ b/server/src/com/cloud/storage/dao/SnapshotScheduleDao.java @@ -39,4 +39,6 @@ public interface SnapshotScheduleDao extends GenericDao executableSchedulesSearch; protected final SearchBuilder coincidingSchedulesSearch; private final SearchBuilder VolumeIdSearch; + private final SearchBuilder VolumeIdPolicyIdSearch; // DB constraint: For a given volume and policyId, there will only be one entry in this table. @@ -57,6 +58,11 @@ public class SnapshotScheduleDaoImpl extends GenericDaoBase sc = VolumeIdPolicyIdSearch.create(); + sc.setParameters("volumeId", volumeId); + sc.setParameters("policyId", policyId); + return findOneBy(sc); + } /** * {@inheritDoc} */ @@ -87,8 +102,6 @@ public class SnapshotScheduleDaoImpl extends GenericDaoBase getSchedulesToExecute(Date currentTimestamp) { SearchCriteria sc = executableSchedulesSearch.create(); sc.setParameters("scheduledTimestamp", currentTimestamp); - // Don't return manual snapshots. They will be executed through another code path. - sc.addAnd("policyId", SearchCriteria.Op.NEQ, 1L); return listBy(sc); } diff --git a/server/src/com/cloud/storage/dao/StoragePoolDaoImpl.java b/server/src/com/cloud/storage/dao/StoragePoolDaoImpl.java index 54e7647e61a..b1f8db25336 100644 --- a/server/src/com/cloud/storage/dao/StoragePoolDaoImpl.java +++ b/server/src/com/cloud/storage/dao/StoragePoolDaoImpl.java @@ -158,7 +158,7 @@ public class StoragePoolDaoImpl extends GenericDaoBase imp public List listByDataCenterId(long datacenterId) { SearchCriteria sc = DatacenterSearch.create(); sc.setParameters("datacenterId", datacenterId); - return listIncludingRemovedBy(sc); + return listBy(sc); } diff --git a/server/src/com/cloud/storage/dao/VolumeDao.java b/server/src/com/cloud/storage/dao/VolumeDao.java index 111db187bcf..03ff2a47156 100755 --- a/server/src/com/cloud/storage/dao/VolumeDao.java +++ b/server/src/com/cloud/storage/dao/VolumeDao.java @@ -23,6 +23,7 @@ import com.cloud.exception.ConcurrentOperationException; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; +import com.cloud.storage.Storage.ImageFormat; import com.cloud.utils.Pair; import com.cloud.utils.db.GenericDao; @@ -55,4 +56,5 @@ public interface VolumeDao extends GenericDao { HypervisorType getHypervisorType(long volumeId); List listVolumesToBeDestroyed(); + ImageFormat getImageFormat(Long volumeId); } diff --git a/server/src/com/cloud/storage/dao/VolumeDaoImpl.java b/server/src/com/cloud/storage/dao/VolumeDaoImpl.java index 62a9d2181c6..9d6a3214110 100755 --- a/server/src/com/cloud/storage/dao/VolumeDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VolumeDaoImpl.java @@ -29,9 +29,12 @@ import javax.ejb.Local; import org.apache.log4j.Logger; import com.cloud.async.AsyncInstanceCreateStatus; +import com.cloud.dc.ClusterVO; import com.cloud.exception.ConcurrentOperationException; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.storage.StoragePool; import com.cloud.storage.Volume; +import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Volume.VolumeType; import com.cloud.storage.VolumeVO; import com.cloud.utils.Pair; @@ -264,6 +267,21 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol } } + @Override + public ImageFormat getImageFormat(Long volumeId) { + HypervisorType type = getHypervisorType(volumeId); + if ( type.equals(HypervisorType.KVM)) { + return ImageFormat.QCOW2; + } else if ( type.equals(HypervisorType.XenServer)) { + return ImageFormat.VHD; + } else if ( type.equals(HypervisorType.VMware)) { + return ImageFormat.OVA; + } else { + s_logger.warn("Do not support hypervisor " + type.toString()); + return null; + } + } + protected VolumeDaoImpl() { AllFieldsSearch = createSearchBuilder(); AllFieldsSearch.and("state", AllFieldsSearch.entity().getState(), Op.EQ); diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManager.java b/server/src/com/cloud/storage/snapshot/SnapshotManager.java index aec47edd75b..8dede26df13 100755 --- a/server/src/com/cloud/storage/snapshot/SnapshotManager.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManager.java @@ -24,6 +24,7 @@ import com.cloud.storage.SnapshotPolicyVO; import com.cloud.storage.SnapshotVO; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.VolumeVO; +import com.cloud.utils.db.Filter; /** * @@ -35,7 +36,7 @@ public interface SnapshotManager { public static final int HOURLYMAX = 8; public static final int DAILYMAX = 8; public static final int WEEKLYMAX = 8; - public static final int MONTHLYMAX = 8; + public static final int MONTHLYMAX = 12; public static final int DELTAMAX = 16; /** @@ -101,8 +102,6 @@ public interface SnapshotManager { */ List listSnapsforVolume(long volumeId); - SnapshotPolicyVO getPolicyForVolumeByInterval(long volumeId, short interval); - void deletePoliciesForVolume(Long volumeId); /** @@ -116,11 +115,9 @@ public interface SnapshotManager { void validateSnapshot(Long userId, SnapshotVO snapshot); - ImageFormat getImageFormat(Long volumeId); - SnapshotPolicyVO getPolicyForVolume(long volumeId); - boolean destroySnapshotBackUp(long snapshotId, long policyId); + boolean destroySnapshotBackUp(long snapshotId); /** * Create a snapshot of a volume @@ -128,4 +125,8 @@ public interface SnapshotManager { * @return the Snapshot that was created */ SnapshotVO createSnapshotOnPrimary(VolumeVO volume, Long polocyId, Long snapshotId) throws ResourceAllocationException; + + List listPoliciesforSnapshot(long snapshotId); + + List listSnapsforPolicy(long policyId, Filter filter); } diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java index 7875a1d3802..c4a9af769ec 100755 --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -26,7 +26,6 @@ import java.util.TimeZone; import javax.ejb.Local; import javax.naming.ConfigurationException; -import javax.persistence.EntityExistsException; import org.apache.log4j.Logger; @@ -74,11 +73,9 @@ import com.cloud.storage.Snapshot.Type; import com.cloud.storage.SnapshotPolicyVO; 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.StoragePool; import com.cloud.storage.StoragePoolVO; -import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.DiskOfferingDao; @@ -86,9 +83,6 @@ import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.SnapshotPolicyDao; import com.cloud.storage.dao.SnapshotScheduleDao; import com.cloud.storage.dao.StoragePoolDao; -import com.cloud.storage.dao.VMTemplateDao; -import com.cloud.storage.dao.VMTemplateHostDao; -import com.cloud.storage.dao.VMTemplatePoolDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.user.Account; import com.cloud.user.AccountManager; @@ -133,9 +127,6 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma @Inject protected SnapshotPolicyDao _snapshotPolicyDao = null; @Inject protected SnapshotScheduleDao _snapshotScheduleDao; @Inject protected DetailsDao _detailsDao; - @Inject protected VMTemplateDao _templateDao; - @Inject protected VMTemplatePoolDao _templatePoolDao; - @Inject protected VMTemplateHostDao _templateHostDao; @Inject protected DomainDao _domainDao; @Inject protected StorageManager _storageMgr; @Inject protected AgentManager _agentMgr; @@ -188,19 +179,7 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma return runSnap; } - - @Override - public ImageFormat getImageFormat(Long volumeId) { - ImageFormat format = null; - VolumeVO volume = _volsDao.findById(volumeId); - Long templateId = volume.getTemplateId(); - if (templateId != null) { - VMTemplateVO template = _templateDao.findById(templateId); - format = template.getFormat(); - } - return format; - } - + protected Answer sendToPool(Volume vol, Command cmd) { StoragePool pool = _storagePoolDao.findById(vol.getPoolId()); VMInstanceVO vm = _vmDao.findById(vol.getInstanceId()); @@ -523,25 +502,18 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_SNAPSHOT_CREATE, snapshot.getAccountId(), volume.getDataCenterId(), snapshotId, snapshot.getName(), null, null, volume.getSize()); _usageEventDao.persist(usageEvent); - if (snapshot.getSnapshotType() == Type.RECURRING.ordinal()) { + if (snapshot.getType() == Type.RECURRING ) { _accountMgr.incrementResourceCount(snapshot.getAccountId(), ResourceType.snapshot); } } else { - // Just mark it as removed in the database. When the next snapshot it taken, - // validate previous snapshot will fix the state. - // It will - // 1) Call backupSnapshotToSecondaryStorage and try again. - // 2) Create the next Snapshot pretending this is a valid snapshot. - // 3) backupSnapshotToSecondaryStorage of the next snapshot - // will take care of cleaning up the state of this snapshot - if (snapshot.getSnapshotType() == Type.RECURRING.ordinal()) { + if (snapshot.getType() == Type.MANUAL ) { _accountMgr.decrementResourceCount(snapshot.getAccountId(), ResourceType.snapshot); - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_SNAPSHOT_DELETE, snapshot.getAccountId(), 0L, snapshotId, snapshot.getName(), null, null, 0L); - _usageEventDao.persist(usageEvent); } + UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_SNAPSHOT_DELETE, snapshot.getAccountId(), 0L, snapshotId, snapshot.getName(), null, null, 0L); + _usageEventDao.persist(usageEvent); _snapshotDao.remove(snapshotId); } txn.commit(); @@ -566,45 +538,42 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma @DB public void postCreateSnapshot(Long volumeId, Long snapshotId, Long policyId, boolean backedUp) { Long userId = getSnapshotUserId(); + SnapshotVO snapshot = _snapshotDao.findByIdIncludingRemoved(snapshotId); // Update the snapshot_policy_ref table with the created snapshot // Get the list of policies for this snapshot - Transaction txn = Transaction.currentTxn(); - txn.start(); if (backedUp) { // This is a manual create, so increment the count of snapshots for // this account - if (policyId == Snapshot.MANUAL_POLICY_ID) { - Snapshot snapshot = _snapshotDao.findByIdIncludingRemoved(snapshotId); + if ( snapshot.getType() == Type.MANUAL) { _accountMgr.incrementResourceCount(snapshot.getAccountId(), ResourceType.snapshot); } } // Even if the current snapshot failed, we should schedule the next // recurring snapshot for this policy. - if (policyId != Snapshot.MANUAL_POLICY_ID) { + if ( snapshot.isRecursive()) { postCreateRecurringSnapshotForPolicy(userId, volumeId, snapshotId, policyId); } - - txn.commit(); } private void postCreateRecurringSnapshotForPolicy(long userId, long volumeId, long snapshotId, long policyId) { //Use count query - List snaps = listSnapsforVolumeType(volumeId, Type.RECURRING.name()); + SnapshotVO spstVO = _snapshotDao.findById(snapshotId); + Type type = spstVO.getType(); + int maxSnaps = type.getMax(); + + List snaps = listSnapsforVolumeType(volumeId, type); SnapshotPolicyVO policy = _snapshotPolicyDao.findById(policyId); - - while(snaps.size() > policy.getMaxSnaps() && snaps.size() > 1) { - //Delete the oldest snap ref in snap_policy_ref + if ( policy != null && policy.getMaxSnaps() < maxSnaps ) { + maxSnaps = policy.getMaxSnaps(); + } + while(snaps.size() > maxSnaps && snaps.size() > 1) { SnapshotVO oldestSnapshot = snaps.get(0); long oldSnapId = oldestSnapshot.getId(); s_logger.debug("Max snaps: "+ policy.getMaxSnaps() + " exceeded for snapshot policy with Id: " + policyId + ". Deleting oldest snapshot: " + oldSnapId); - // Excess snapshot. delete it asynchronously - //destroySnapshotAsync(userId, volumeId, oldSnapId, policyId); - // create the event - deleteSnapshotInternal(oldSnapId, policyId); + deleteSnapshotInternal(oldSnapId); snaps.remove(oldestSnapshot); } - } private Long checkAccountPermissions(long targetAccountId, long targetDomainId, String targetDesc, long targetId) { @@ -648,33 +617,18 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma } checkAccountPermissions(snapshotOwner.getId(), snapshotOwner.getDomainId(), "snapshot", snapshotId); - boolean status = true; - if (Type.MANUAL.ordinal() == snapshotCheck.getSnapshotType()) { - status = deleteSnapshotInternal(snapshotId, Snapshot.MANUAL_POLICY_ID); - - if (!status) { - s_logger.warn("Failed to delete snapshot"); - throw new CloudRuntimeException("Failed to delete snapshot:"+snapshotId); - } - } else { - List policies = listPoliciesforVolume(snapshotCheck.getVolumeId()); - - for (SnapshotPolicyVO policy : policies) { - status = deleteSnapshotInternal(snapshotId, policy.getId()); - - if (!status) { - s_logger.warn("Failed to delete snapshot"); - throw new CloudRuntimeException("Failed to delete snapshot:"+snapshotId); - } - } + boolean status = deleteSnapshotInternal(snapshotId); + if (!status) { + s_logger.warn("Failed to delete snapshot"); + throw new CloudRuntimeException("Failed to delete snapshot:" + snapshotId); } - + return status; } - private boolean deleteSnapshotInternal(Long snapshotId, Long policyId) { + private boolean deleteSnapshotInternal(Long snapshotId) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Calling deleteSnapshot for snapshotId: " + snapshotId + " and policyId " + policyId); + s_logger.debug("Calling deleteSnapshot for snapshotId: " + snapshotId ); } SnapshotVO lastSnapshot = null; SnapshotVO snapshot = _snapshotDao.findById(snapshotId); @@ -713,7 +667,7 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma lastSnapshot.setBackupSnapshotId(null); _snapshotDao.update(lastSnapshot.getId(), lastSnapshot); } else { - if (destroySnapshotBackUp(lastId, policyId)) { + if (destroySnapshotBackUp(lastId)) { } else { s_logger.debug("Destroying snapshot backup failed " + lastSnapshot); @@ -721,7 +675,7 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma } } } - postDeleteSnapshot(lastId, policyId); + postDeleteSnapshot(lastId); lastId = lastSnapshot.getPrevSnapshotId(); if (lastId == 0) { break; @@ -738,60 +692,58 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma } @Override @DB - public boolean destroySnapshotBackUp(long snapshotId, long policyId) { + public boolean destroySnapshotBackUp(long snapshotId) { boolean success = false; - String details = null; + String details; SnapshotVO snapshot = _snapshotDao.findByIdIncludingRemoved(snapshotId); - - VolumeVO volume = _volsDao.findByIdIncludingRemoved(snapshot.getVolumeId()); - if ( volume == null ) { - throw new CloudRuntimeException("Destroying snapshot " + snapshotId + " backup failed due to unable to find volume " + snapshot.getVolumeId()); + if ( snapshot == null ) { + throw new CloudRuntimeException("Destroying snapshot " + snapshotId + " backup failed due to unable to find snapshot "); } - String primaryStoragePoolNameLabel = _storageMgr.getPrimaryStorageNameLabel(volume); - String secondaryStoragePoolUrl = _storageMgr.getSecondaryStorageURL(volume.getDataCenterId()); - Long dcId = volume.getDataCenterId(); - Long accountId = volume.getAccountId(); - Long volumeId = volume.getId(); + + String secondaryStoragePoolUrl = _storageMgr.getSecondaryStorageURL(snapshot.getDataCenterId()); + Long dcId = snapshot.getDataCenterId(); + Long accountId = snapshot.getAccountId(); + Long volumeId = snapshot.getVolumeId(); + HypervisorType hvType = snapshot.getHypervisorType(); String backupOfSnapshot = snapshot.getBackupSnapshotId(); if ( backupOfSnapshot == null ) { return true; } - DeleteSnapshotBackupCommand cmd = new DeleteSnapshotBackupCommand(primaryStoragePoolNameLabel, + DeleteSnapshotBackupCommand cmd = new DeleteSnapshotBackupCommand(null, secondaryStoragePoolUrl, dcId, accountId, volumeId, backupOfSnapshot, snapshot.getName()); snapshot.setBackupSnapshotId(null); _snapshotDao.update(snapshotId, snapshot); - details = "Failed to destroy snapshot id:" + snapshotId + " for volume: " + volume.getId(); - Answer answer = sendToPool(volume, cmd); + + Answer answer = _agentMgr.sendTo(dcId, hvType, cmd); if ((answer != null) && answer.getResult()) { // This is not the last snapshot. success = true; - details = "Successfully deleted snapshot " + snapshotId + " for volumeId: " + volumeId + " and policyId " - + policyId; + details = "Successfully deleted snapshot " + snapshotId + " for volumeId: " + volumeId ; s_logger.debug(details); } else if (answer != null) { + details = "Failed to destroy snapshot id:" + snapshotId + " for volume: " + volumeId + " due to "; if (answer.getDetails() != null) { - details = answer.getDetails(); + details += answer.getDetails(); } s_logger.error(details); } - return success; } @DB - protected void postDeleteSnapshot(long snapshotId, long policyId) { + protected void postDeleteSnapshot(long snapshotId) { // Remove the snapshot from the snapshots table and the snap_policy_ref table. Transaction txn = Transaction.currentTxn(); txn.start(); SnapshotVO snapshot = _snapshotDao.findByIdIncludingRemoved(snapshotId); // If this is a manual delete, decrement the count of snapshots for this account - if (policyId == Snapshot.MANUAL_POLICY_ID) { + if (snapshot.getType() == Type.MANUAL) { _accountMgr.decrementResourceCount(snapshot.getAccountId(), ResourceType.snapshot); } @@ -807,10 +759,10 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma // Verify parameters if(volumeId != null){ VolumeVO volume = _volsDao.findById(volumeId); - if (volume == null) { - throw new InvalidParameterValueException("unable to find a volume with id " + volumeId); + if (volume != null) { + checkAccountPermissions(volume.getAccountId(), volume.getDomainId(), "volume", volumeId); } - checkAccountPermissions(volume.getAccountId(), volume.getDomainId(), "volume", volumeId); + } Account account = UserContext.current().getCaller(); @@ -855,8 +807,8 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma sb.and("name", sb.entity().getName(), SearchCriteria.Op.LIKE); sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); sb.and("accountId", sb.entity().getAccountId(), SearchCriteria.Op.EQ); - sb.and("snapshotTypeEQ", sb.entity().getSnapshotType(), SearchCriteria.Op.EQ); - sb.and("snapshotTypeNEQ", sb.entity().getSnapshotType(), SearchCriteria.Op.NEQ); + sb.and("snapshotTypeEQ", sb.entity().getsnapshotType(), SearchCriteria.Op.IN); + sb.and("snapshotTypeNEQ", sb.entity().getsnapshotType(), SearchCriteria.Op.NEQ); if ((accountId == null) && (domainId != null)) { // if accountId isn't specified, we can do a domain match for the admin case @@ -912,9 +864,17 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma if (snapshotType == null) { throw new InvalidParameterValueException("Unsupported snapshot type " + snapshotTypeStr); } - sc.setParameters("snapshotTypeEQ", snapshotType.ordinal()); + if ( snapshotType == Type.RECURRING ) { + sc.setParameters("snapshotTypeEQ", Type.HOURLY.ordinal(), Type.DAILY.ordinal(), Type.WEEKLY.ordinal(), Type.MONTHLY.ordinal() ); + } else { + sc.setParameters("snapshotTypeEQ", snapshotType.ordinal()); + } } else if (intervalTypeStr != null && volumeId != null) { - sc.setParameters("snapshotTypeEQ", Snapshot.Type.RECURRING.ordinal()); + Type type = SnapshotVO.getSnapshotType((String)intervalTypeStr); + if ( type == null ) { + throw new InvalidParameterValueException("Unsupported snapstho interval type " + intervalTypeStr); + } + sc.setParameters("snapshotTypeEQ", type.ordinal()); } else { // Show only MANUAL and RECURRING snapshot types sc.setParameters("snapshotTypeNEQ", Snapshot.Type.TEMPLATE.ordinal()); @@ -973,7 +933,9 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma List snapshots = listSnapsforVolume(volumeId); for (SnapshotVO snapshot: snapshots) { if(_snapshotDao.expunge(snapshot.getId())){ - _accountMgr.decrementResourceCount(accountId, ResourceType.snapshot); + if ( snapshot.getType() == Type.MANUAL ) { + _accountMgr.decrementResourceCount(accountId, ResourceType.snapshot); + } //Log event after successful deletion UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_SNAPSHOT_DELETE, snapshot.getAccountId(), volume.getDataCenterId(), snapshot.getId(), snapshot.getName(), null, null, volume.getSize()); @@ -1008,32 +970,32 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma throw new InvalidParameterValueException("Failed to create snapshot policy, snapshots of volumes attached to System or router VM are not allowed"); } } - IntervalType type = DateUtil.IntervalType.getIntervalType(cmd.getIntervalType()); - if (type == null) { + IntervalType intvType = DateUtil.IntervalType.getIntervalType(cmd.getIntervalType()); + if (intvType == null) { throw new InvalidParameterValueException("Unsupported interval type " + cmd.getIntervalType()); } + Type type = getSnapshotType(intvType); 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); + DateUtil.getNextRunTime(intvType, cmd.getSchedule(), timezoneId, null); } catch (Exception e){ throw new InvalidParameterValueException("Invalid schedule: "+ cmd.getSchedule() +" for interval type: " + cmd.getIntervalType()); } + + if (cmd.getMaxSnaps() <=0) { + throw new InvalidParameterValueException("maxSnaps should be greater than 0"); + } int intervalMaxSnaps = type.getMax(); if (cmd.getMaxSnaps() > intervalMaxSnaps) { throw new InvalidParameterValueException("maxSnaps exceeds limit: " + intervalMaxSnaps + " for interval type: " + cmd.getIntervalType()); } - if (cmd.getMaxSnaps() <=0) { - throw new InvalidParameterValueException("maxSnaps should be greater than 0"); - } - //Verify that max doesn't exceed domain and account snapshot limits long accountLimit = _accountMgr.findCorrectResourceLimit(owner, ResourceType.snapshot); long domainLimit = _accountMgr.findCorrectResourceLimit(domain, ResourceType.snapshot); @@ -1042,17 +1004,17 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma throw new InvalidParameterValueException("Max number of snapshots shouldn't exceed the domain/account level snapshot limit"); } - SnapshotPolicyVO policy = new SnapshotPolicyVO(volumeId, cmd.getSchedule(), timezoneId, (short)type.ordinal(), cmd.getMaxSnaps()); - // Create an event - try{ + SnapshotPolicyVO policy = _snapshotPolicyDao.findOneByVolumeInterval(volumeId, intvType); + if ( policy == null ) { + policy = new SnapshotPolicyVO(volumeId, cmd.getSchedule(), timezoneId, intvType, cmd.getMaxSnaps()); policy = _snapshotPolicyDao.persist(policy); - } catch (EntityExistsException e ) { - policy = _snapshotPolicyDao.findOneByVolume(volumeId); + _snapSchedMgr.scheduleNextSnapshotJob(policy); + } else { try { policy = _snapshotPolicyDao.acquireInLockTable(policy.getId()); policy.setSchedule(cmd.getSchedule()); policy.setTimezone(timezoneId); - policy.setInterval((short)type.ordinal()); + policy.setInterval((short) type.ordinal()); policy.setMaxSnaps(cmd.getMaxSnaps()); policy.setActive(true); _snapshotPolicyDao.update(policy.getId(), policy); @@ -1061,8 +1023,8 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma _snapshotPolicyDao.releaseFromLockTable(policy.getId()); } } + } - _snapSchedMgr.scheduleNextSnapshotJob(policy); return policy; } @@ -1088,7 +1050,7 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma public List listPoliciesforVolume(long volumeId) { return _snapshotPolicyDao.listByVolumeId(volumeId); } -/* + @Override public List listPoliciesforSnapshot(long snapshotId) { SearchCriteria sc = PoliciesForSnapSearch.create(); @@ -1102,14 +1064,14 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma sc.setJoinParameters("policy", "policyId", policyId); return _snapshotDao.search(sc, filter); } -*/ + @Override public List listSnapsforVolume(long volumeId) { return _snapshotDao.listByVolumeId(volumeId); } - public List listSnapsforVolumeType(long volumeId, String type) { + public List listSnapsforVolumeType(long volumeId, Type type) { return _snapshotDao.listByVolumeIdType(volumeId, type); } @@ -1170,16 +1132,35 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma return snapshotSchedules; } - @Override - public SnapshotPolicyVO getPolicyForVolumeByInterval(long volumeId, short interval) { - return _snapshotPolicyDao.findOneByVolumeInterval(volumeId, interval); - } - @Override public SnapshotPolicyVO getPolicyForVolume(long volumeId) { return _snapshotPolicyDao.findOneByVolume(volumeId); } + + public Type getSnapshotType(Long policyId) { + if (policyId.equals(Snapshot.MANUAL_POLICY_ID)) { + return Type.MANUAL; + } else { + SnapshotPolicyVO spstPolicyVO = _snapshotPolicyDao.findById(policyId); + IntervalType intvType = DateUtil.getIntervalType(spstPolicyVO.getInterval()); + return getSnapshotType(intvType); + } + } + + public Type getSnapshotType(IntervalType intvType) { + if (intvType.equals(IntervalType.HOURLY)) { + return Type.HOURLY; + } else if (intvType.equals(IntervalType.DAILY)) { + return Type.DAILY; + } else if (intvType.equals(IntervalType.WEEKLY)) { + return Type.WEEKLY; + } else if (intvType.equals(IntervalType.MONTHLY)) { + return Type.MONTHLY; + } + return null; + } + @Override public SnapshotVO allocSnapshot(CreateSnapshotCmd cmd) { Long volumeId = cmd.getVolumeId(); @@ -1208,10 +1189,10 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma // Create the Snapshot object and save it so we can return it to the // user - Type snapshotType = SnapshotVO.getSnapshotType(policyId); + Type snapshotType = getSnapshotType(policyId); HypervisorType hypervisorType = this._volsDao.getHypervisorType(volumeId); - SnapshotVO snapshotVO = new SnapshotVO(volume.getAccountId(), volume.getId(), null, snapshotName, - (short) snapshotType.ordinal(), snapshotType.name(), hypervisorType); + SnapshotVO snapshotVO = new SnapshotVO(volume.getDataCenterId(), volume.getAccountId(), volume.getDomainId(), volume.getId(), null, snapshotName, + (short) snapshotType.ordinal(), snapshotType.name(), volume.getSize(), hypervisorType); return _snapshotDao.persist(snapshotVO); } @@ -1226,10 +1207,10 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma throw new ConfigurationException("Unable to get the configuration dao."); } - 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)); - DateUtil.IntervalType.MONTHLY.setMax(NumbersUtil.parseInt(configDao.getValue("snapshot.max.monthly"), MONTHLYMAX)); + Type.HOURLY.setMax(NumbersUtil.parseInt(configDao.getValue("snapshot.max.hourly"), HOURLYMAX)); + Type.DAILY.setMax(NumbersUtil.parseInt(configDao.getValue("snapshot.max.daily"), DAILYMAX)); + Type.WEEKLY.setMax(NumbersUtil.parseInt(configDao.getValue("snapshot.max.weekly"), WEEKLYMAX)); + Type.MONTHLY.setMax(NumbersUtil.parseInt(configDao.getValue("snapshot.max.monthly"), MONTHLYMAX)); _deltaSnapshotMax = NumbersUtil.parseInt(configDao.getValue("snapshot.delta.max"), DELTAMAX); _totalRetries = NumbersUtil.parseInt(configDao.getValue("total.retries"), 4); _pauseInterval = 2*NumbersUtil.parseInt(configDao.getValue("ping.interval"), 60); diff --git a/server/src/com/cloud/storage/snapshot/SnapshotSchedulerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotSchedulerImpl.java index d60528b3aad..a1d205462c8 100644 --- a/server/src/com/cloud/storage/snapshot/SnapshotSchedulerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotSchedulerImpl.java @@ -26,7 +26,6 @@ import java.util.TimerTask; import javax.ejb.Local; import javax.naming.ConfigurationException; -import javax.persistence.EntityExistsException; import org.apache.log4j.Logger; @@ -133,7 +132,7 @@ public class SnapshotSchedulerImpl implements SnapshotScheduler { } } finally { scanLock.releaseRef(); - } + } } private void checkStatusOfCurrentlyExecutingSnapshots() { @@ -182,7 +181,7 @@ public class SnapshotSchedulerImpl implements SnapshotScheduler { // If the snapshot was taken successfully on primary, it will retry backing it up. // and cleanup the previous snapshot // Set the userId to that of system. - _snapshotManager.validateSnapshot(1L, snapshot); + //_snapshotManager.validateSnapshot(1L, snapshot); // In all cases, schedule the next snapshot job scheduleNextSnapshotJob(snapshotSchedule); } @@ -222,6 +221,9 @@ public class SnapshotSchedulerImpl implements SnapshotScheduler { // this volume is not attached continue; } + if ( _snapshotPolicyDao.findById(policyId) == null ) { + _snapshotScheduleDao.remove(snapshotToBeExecuted.getId()); + } if (s_logger.isDebugEnabled()) { Date scheduledTimestamp = snapshotToBeExecuted.getScheduledTimestamp(); displayTime = DateUtil.displayDateInTimezone(DateUtil.GMT_TIMEZONE, scheduledTimestamp); @@ -270,38 +272,46 @@ public class SnapshotSchedulerImpl implements SnapshotScheduler { } private Date scheduleNextSnapshotJob(SnapshotScheduleVO snapshotSchedule) { - Long policyId = snapshotSchedule.getPolicyId(); - Long expectedId = snapshotSchedule.getId(); - if (_snapshotScheduleDao.findById(expectedId) != null) { - // We need to acquire a lock and delete it, then release the lock. - // But I don't know how to. - _snapshotScheduleDao.expunge(expectedId); + if ( snapshotSchedule == null ) { + return null; } + Long policyId = snapshotSchedule.getPolicyId(); if (policyId.longValue() == Snapshot.MANUAL_POLICY_ID) { // Don't need to schedule the next job for this. return null; } SnapshotPolicyVO snapshotPolicy = _snapshotPolicyDao.findById(policyId); + if ( snapshotPolicy == null ) { + _snapshotScheduleDao.expunge(snapshotSchedule.getId()); + } return scheduleNextSnapshotJob(snapshotPolicy); } @Override @DB - public Date scheduleNextSnapshotJob(SnapshotPolicyVO policyInstance) { - long policyId = policyInstance.getId(); - Date nextSnapshotTimestamp = getNextScheduledTime(policyId, new Date()); - SnapshotScheduleVO snapshotScheduleVO = new SnapshotScheduleVO(policyInstance.getVolumeId(), policyId, nextSnapshotTimestamp); - try{ - _snapshotScheduleDao.persist(snapshotScheduleVO); - } catch (EntityExistsException e ) { - snapshotScheduleVO = _snapshotScheduleDao.findOneByVolume(policyInstance.getVolumeId()); - try { - snapshotScheduleVO = _snapshotScheduleDao.acquireInLockTable(snapshotScheduleVO.getId()); - snapshotScheduleVO.setPolicyId(policyId); - snapshotScheduleVO.setScheduledTimestamp(nextSnapshotTimestamp); - _snapshotScheduleDao.update(snapshotScheduleVO.getId(), snapshotScheduleVO); + public Date scheduleNextSnapshotJob(SnapshotPolicyVO policy) { + if ( policy == null) { + return null; + } + long policyId = policy.getId(); + if ( policyId == Snapshot.MANUAL_POLICY_ID ) { + return null; + } + Date nextSnapshotTimestamp = getNextScheduledTime(policyId, _currentTimestamp); + SnapshotScheduleVO spstSchedVO = _snapshotScheduleDao.findOneByVolumePolicy(policy.getVolumeId(), policy.getId()); + if ( spstSchedVO == null ) { + spstSchedVO = new SnapshotScheduleVO(policy.getVolumeId(), policyId, nextSnapshotTimestamp); + _snapshotScheduleDao.persist(spstSchedVO); + } else { + try{ + spstSchedVO = _snapshotScheduleDao.acquireInLockTable(spstSchedVO.getId()); + spstSchedVO.setPolicyId(policyId); + spstSchedVO.setScheduledTimestamp(nextSnapshotTimestamp); + spstSchedVO.setAsyncJobId(null); + spstSchedVO.setSnapshotId(null); + _snapshotScheduleDao.update(spstSchedVO.getId(), spstSchedVO); } finally { - if(snapshotScheduleVO != null ) { - _snapshotScheduleDao.releaseFromLockTable(snapshotScheduleVO.getId()); + if(spstSchedVO != null ) { + _snapshotScheduleDao.releaseFromLockTable(spstSchedVO.getId()); } } } @@ -316,7 +326,7 @@ public class SnapshotSchedulerImpl implements SnapshotScheduler { SnapshotScheduleVO schedule = _snapshotScheduleDao.getCurrentSchedule(volumeId, policyId, false); boolean success = true; if (schedule != null) { - success = _snapshotScheduleDao.expunge(schedule.getId()); + success = _snapshotScheduleDao.remove(schedule.getId()); } if(!success){ s_logger.debug("Error while deleting Snapshot schedule with Id: "+schedule.getId()); diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 34ce7688501..f9190ffe894 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -19,7 +19,6 @@ package com.cloud.vm; import java.util.ArrayList; import java.util.Date; -import java.util.Formatter; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -133,7 +132,6 @@ import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.Storage.StorageResourceType; import com.cloud.storage.Storage.TemplateType; import com.cloud.storage.StorageManager; -import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolStatus; import com.cloud.storage.StoragePoolVO; import com.cloud.storage.VMTemplateHostVO; @@ -1194,106 +1192,107 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager if (user == null) { throw new InvalidParameterValueException("User " + userId + " does not exist"); - } - - Long volumeId = cmd.getVolumeId(); - Long snapshotId = cmd.getSnapshotId(); - if (volumeId == null) { - if (snapshotId == null) { - throw new InvalidParameterValueException("Failed to create private template record, neither volume ID nor snapshot ID were specified."); - } - SnapshotVO snapshot = _snapshotDao.findById(snapshotId); - if (snapshot == null) { - throw new InvalidParameterValueException("Failed to create private template record, unable to find snapshot " + snapshotId); - } - volumeId = snapshot.getVolumeId(); - } else { - if (snapshotId != null) { - throw new InvalidParameterValueException("Failed to create private template record, please specify only one of volume ID (" + volumeId + ") and snapshot ID (" + snapshotId + ")"); - } - } - - VolumeVO volume = _volsDao.findById(volumeId); - if (volume == null) { - throw new InvalidParameterValueException("Volume with ID: " + volumeId + " does not exist"); - } - - if (!isAdmin) { - if (account.getId() != volume.getAccountId()) { - throw new PermissionDeniedException("Unable to create a template from volume with id " + volumeId + ", permission denied."); - } - } else if ((account != null) && !_domainDao.isChildDomain(account.getDomainId(), volume.getDomainId())) { - throw new PermissionDeniedException("Unable to create a template from volume with id " + volumeId + ", permission denied."); - } + } String name = cmd.getTemplateName(); if ((name == null) || (name.length() > 32)) { throw new InvalidParameterValueException("Template name cannot be null and should be less than 32 characters"); } - String uniqueName = Long.valueOf((userId == null)?1:userId).toString() + Long.valueOf(volumeId).toString() + UUID.nameUUIDFromBytes(name.getBytes()).toString(); - - VMTemplateVO existingTemplate = _templateDao.findByTemplateNameAccountId(name, volume.getAccountId()); - if (existingTemplate != null) { - throw new InvalidParameterValueException("Failed to create private template " + name + ", a template with that name already exists."); - } - - AccountVO ownerAccount = _accountDao.findById(volume.getAccountId()); - if (_accountMgr.resourceLimitExceeded(ownerAccount, ResourceType.template)) { - ResourceAllocationException rae = new ResourceAllocationException("Maximum number of templates and ISOs for account: " + account.getAccountName() + " has been exceeded."); - rae.setResourceType("template"); - throw rae; - } // do some parameter defaulting - Integer bits = cmd.getBits(); - Boolean requiresHvm = cmd.getRequiresHvm(); - Boolean passwordEnabled = cmd.isPasswordEnabled(); - Boolean isPublic = cmd.isPublic(); - Boolean featured = cmd.isFeatured(); - - HypervisorType hyperType = _volsDao.getHypervisorType(volumeId); - int bitsValue = ((bits == null) ? 64 : bits.intValue()); - boolean requiresHvmValue = ((requiresHvm == null) ? true : requiresHvm.booleanValue()); - boolean passwordEnabledValue = ((passwordEnabled == null) ? false : passwordEnabled.booleanValue()); + Integer bits = cmd.getBits(); + Boolean requiresHvm = cmd.getRequiresHvm(); + Boolean passwordEnabled = cmd.isPasswordEnabled(); + Boolean isPublic = cmd.isPublic(); + Boolean featured = cmd.isFeatured(); + int bitsValue = ((bits == null) ? 64 : bits.intValue()); + boolean requiresHvmValue = ((requiresHvm == null) ? true : requiresHvm.booleanValue()); + boolean passwordEnabledValue = ((passwordEnabled == null) ? false : passwordEnabled.booleanValue()); if (isPublic == null) { isPublic = Boolean.FALSE; - } - - if (!isAdmin || featured == null) { - featured = Boolean.FALSE; } - boolean allowPublicUserTemplates = Boolean.parseBoolean(_configDao.getValue("allow.public.user.templates")); if (!isAdmin && !allowPublicUserTemplates && isPublic) { throw new PermissionDeniedException("Failed to create template " + name + ", only private templates can be created."); } - - // if the volume is a root disk, try to find out requiresHvm and bits if possible - if (Volume.VolumeType.ROOT.equals(volume.getVolumeType())) { - Long instanceId = volume.getInstanceId(); - if (instanceId != null) { - UserVm vm = _vmDao.findById(instanceId); - if (vm != null) { - VMTemplateVO origTemplate = _templateDao.findById(vm.getTemplateId()); - if (!ImageFormat.ISO.equals(origTemplate.getFormat()) && !ImageFormat.RAW.equals(origTemplate.getFormat())) { - bitsValue = origTemplate.getBits(); - requiresHvmValue = origTemplate.requiresHvm(); - } - } + + Long volumeId = cmd.getVolumeId(); + Long snapshotId = cmd.getSnapshotId(); + if ( (volumeId == null) && (snapshotId == null) ) { + throw new InvalidParameterValueException("Failed to create private template record, neither volume ID nor snapshot ID were specified."); + } + if ( (volumeId != null) && (snapshotId != null) ) { + throw new InvalidParameterValueException("Failed to create private template record, please specify only one of volume ID (" + volumeId + ") and snapshot ID (" + snapshotId + ")"); + } + + long domainId; + long accountId; + HypervisorType hyperType; + VolumeVO volume = null; + if (volumeId != null) { // create template from volume + volume = _volsDao.findById(volumeId); + if (volume == null) { + throw new InvalidParameterValueException("Failed to create private template record, unable to find volume " + volumeId); } + // If private template is created from Volume, check that the volume will not be active when the private template is created + if (!_storageMgr.volumeInactive(volume)) { + String msg = "Unable to create private template for volume: " + volume.getName() + "; volume is attached to a non-stopped VM, please stop the VM first" ; + if (s_logger.isInfoEnabled()) { + s_logger.info(msg); + } + throw new CloudRuntimeException(msg); + } + domainId = volume.getDomainId(); + accountId = volume.getAccountId(); + hyperType = _volsDao.getHypervisorType(volumeId); + } else { // create template from snapshot + SnapshotVO snapshot = _snapshotDao.findById(snapshotId); + if (snapshot == null) { + throw new InvalidParameterValueException("Failed to create private template record, unable to find snapshot " + snapshotId); + } + domainId = snapshot.getDomainId(); + accountId = snapshot.getAccountId(); + hyperType = snapshot.getHypervisorType(); + volume = _volsDao.findById(snapshot.getVolumeId()); } + if (!isAdmin) { + if (account.getId() != accountId) { + throw new PermissionDeniedException("Unable to create a template permission denied."); + } + } else if ((account != null) && !_domainDao.isChildDomain(account.getDomainId(), domainId)) { + throw new PermissionDeniedException("Unable to create a template permission denied."); + } + + VMTemplateVO existingTemplate = _templateDao.findByTemplateNameAccountId(name, accountId); + if (existingTemplate != null) { + throw new InvalidParameterValueException("Failed to create private template " + name + ", a template with that name already exists."); + } + + AccountVO ownerAccount = _accountDao.findById(accountId); + if (_accountMgr.resourceLimitExceeded(ownerAccount, ResourceType.template)) { + ResourceAllocationException rae = new ResourceAllocationException("Maximum number of templates and ISOs for account: " + account.getAccountName() + " has been exceeded."); + rae.setResourceType("template"); + throw rae; + } + + if (!isAdmin || featured == null) { + featured = Boolean.FALSE; + } Long guestOSId = cmd.getOsTypeId(); GuestOSVO guestOS = _guestOSDao.findById(guestOSId); if (guestOS == null) { throw new InvalidParameterValueException("GuestOS with ID: " + guestOSId + " does not exist."); } - + + String uniqueName = Long.valueOf((userId == null)?1:userId).toString() + UUID.nameUUIDFromBytes(name.getBytes()).toString(); Long nextTemplateId = _templateDao.getNextInSequence(Long.class, "id"); String description = cmd.getDisplayText(); - VMTemplateVO template = ApiDBUtils.findTemplateById(volume.getTemplateId()); - boolean isExtractable = template != null && template.isExtractable() && template.getTemplateType() != Storage.TemplateType.SYSTEM ; - + boolean isExtractable = false; + if ( volume != null ) { + VMTemplateVO template = ApiDBUtils.findTemplateById(volume.getTemplateId()); + isExtractable = template != null && template.isExtractable() && template.getTemplateType() != Storage.TemplateType.SYSTEM ; + } privateTemplate = new VMTemplateVO(nextTemplateId, uniqueName, name, @@ -1306,7 +1305,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager null, requiresHvmValue, bitsValue, - volume.getAccountId(), + accountId, null, description, passwordEnabledValue, @@ -1326,66 +1325,48 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager long templateId = command.getEntityId(); Long volumeId = command.getVolumeId(); Long snapshotId = command.getSnapshotId(); - SnapshotVO snapshot = null; - - // Verify input parameters - if (snapshotId != null) { - snapshot = _snapshotDao.findById(snapshotId); - - // Set the volumeId to that of the snapshot. All further input parameter checks will be done w.r.t the volume. - volumeId = snapshot.getVolumeId(); - } - - // The volume below could be destroyed or removed. - VolumeVO volume = _volsDao.findById(volumeId); - String vmName = _storageMgr.getVmNameOnVolume(volume); - - // If private template is created from Volume, check that the volume will not be active when the private template is created - if (snapshotId == null && !_storageMgr.volumeInactive(volume)) { - String msg = "Unable to create private template for volume: " + volume.getName() + "; volume is attached to a non-stopped VM."; - - if (s_logger.isInfoEnabled()) { - s_logger.info(msg); - } - throw new CloudRuntimeException(msg); - } - SnapshotCommand cmd = null; VMTemplateVO privateTemplate = null; - long zoneId = volume.getDataCenterId(); + String uniqueName = getRandomPrivateTemplateName(); - HostVO secondaryStorageHost = _storageMgr.getSecondaryStorageHost(zoneId); - String secondaryStorageURL = _storageMgr.getSecondaryStorageURL(zoneId); - if (secondaryStorageHost == null || secondaryStorageURL == null) { - throw new CloudRuntimeException("Did not find the secondary storage URL in the database for zoneId " - + zoneId); - } - - if (snapshotId != null) { - volume = _volsDao.findById(volumeId); - StringBuilder userFolder = new StringBuilder(); - Formatter userFolderFormat = new Formatter(userFolder); - userFolderFormat.format("u%06d", snapshot.getAccountId()); + StoragePoolVO pool = null; + HostVO secondaryStorageHost = null; + long zoneId; + Long accountId = null; + if (snapshotId != null) { // create template from snapshot + SnapshotVO snapshot = _snapshotDao.findById(snapshotId); + if( snapshot == null ) { + throw new CloudRuntimeException("Unable to find Snapshot for Id " + snapshotId); + } + zoneId = snapshot.getDataCenterId(); + secondaryStorageHost = _storageMgr.getSecondaryStorageHost(zoneId); + if ( secondaryStorageHost == null ) { + throw new CloudRuntimeException("Can not find the secondary storage for zoneId " + zoneId); + } + String secondaryStorageURL = secondaryStorageHost.getStorageUrl(); String name = command.getTemplateName(); String backupSnapshotUUID = snapshot.getBackupSnapshotId(); if (backupSnapshotUUID == null) { throw new CloudRuntimeException("Unable to create private template from snapshot " + snapshotId + " due to there is no backupSnapshotUUID for this snapshot"); } - - // We are creating a private template from a snapshot which has been - // backed up to secondary storage. - Long dcId = volume.getDataCenterId(); - Long accountId = volume.getAccountId(); + + Long dcId = snapshot.getDataCenterId(); + accountId = snapshot.getAccountId(); + volumeId = snapshot.getVolumeId(); String origTemplateInstallPath = null; - - cmd = new CreatePrivateTemplateFromSnapshotCommand(_storageMgr.getPrimaryStorageNameLabel(volume), + List storagePools = _storagePoolDao.listByDataCenterId(zoneId); + if( storagePools == null || storagePools.size() == 0) { + throw new CloudRuntimeException("Unable to find storage pools in zone " + zoneId); + } + pool = storagePools.get(0); + cmd = new CreatePrivateTemplateFromSnapshotCommand(pool.getUuid(), secondaryStorageURL, dcId, accountId, snapshot.getVolumeId(), backupSnapshotUUID, snapshot.getName(), origTemplateInstallPath, templateId, name); - } else if (volumeId != null) { - volume = _volsDao.findById(volumeId); + } else if (volumeId != null) { + VolumeVO volume = _volsDao.findById(volumeId); if( volume == null ) { throw new CloudRuntimeException("Unable to find volume for Id " + volumeId); } @@ -1393,14 +1374,15 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager _templateDao.remove(templateId); throw new CloudRuntimeException("Volume " + volumeId + " is empty, can't create template on it"); } - Long instanceId = volume.getInstanceId(); - if (instanceId != null){ - VMInstanceVO vm = _vmDao.findById(instanceId); - State vmState = vm.getState(); - if( !vmState.equals(State.Stopped) && !vmState.equals(State.Destroyed)) { - throw new CloudRuntimeException("Please put VM " + vm.getName() + " into Stopped state first"); - } - } + String vmName = _storageMgr.getVmNameOnVolume(volume); + zoneId = volume.getDataCenterId(); + secondaryStorageHost = _storageMgr.getSecondaryStorageHost(zoneId); + if ( secondaryStorageHost == null ) { + throw new CloudRuntimeException("Can not find the secondary storage for zoneId " + zoneId); + } + String secondaryStorageURL = secondaryStorageHost.getStorageUrl(); + + pool = _storagePoolDao.findById(volume.getPoolId()); cmd = new CreatePrivateTemplateFromVolumeCommand(secondaryStorageURL, templateId, volume.getAccountId(), command.getTemplateName(), uniqueName, volume.getPath(), vmName); @@ -1411,35 +1393,18 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager // on the storage server to create the template // This can be sent to a KVM host too. - StoragePool pool = _storagePoolDao.findById(volume.getPoolId()); CreatePrivateTemplateAnswer answer = null; - volume = _volsDao.acquireInLockTable(volumeId, 10); - if( volume == null ) { + if( ! _volsDao.lockInLockTable(volumeId.toString(), 10)) { throw new CloudRuntimeException("Creating template failed due to volume:" + volumeId + " is being used, try it later "); } try { answer = (CreatePrivateTemplateAnswer)_storageMgr.sendToPool(pool, cmd); } catch (StorageUnavailableException e) { } finally { - _volsDao.releaseFromLockTable(volumeId); + _volsDao.unlockFromLockTable(volumeId.toString()); } - if ((answer != null) && answer.getResult()) { privateTemplate = _templateDao.findById(templateId); - Long origTemplateId = volume.getTemplateId(); - VMTemplateVO origTemplate = null; - if (origTemplateId != null) { - origTemplate = _templateDao.findById(origTemplateId); - } - - if ((origTemplate != null) && !Storage.ImageFormat.ISO.equals(origTemplate.getFormat())) { - privateTemplate.setRequiresHvm(origTemplate.requiresHvm()); - privateTemplate.setBits(origTemplate.getBits()); - } else { - privateTemplate.setRequiresHvm(true); - privateTemplate.setBits(64); - } - String answerUniqueName = answer.getUniqueName(); if (answerUniqueName != null) { privateTemplate.setUniqueName(answerUniqueName); @@ -1454,11 +1419,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager // Specify RAW format makes it unusable for snapshots. privateTemplate.setFormat(ImageFormat.RAW); } - - if(snapshot != null) { - privateTemplate.setHypervisorType(snapshot.getHypervisorType()); - } - + _templateDao.update(templateId, privateTemplate); // add template zone ref for this template @@ -1476,7 +1437,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager _usageEventDao.persist(usageEvent); // Increment the number of templates - _accountMgr.incrementResourceCount(volume.getAccountId(), ResourceType.template); + _accountMgr.incrementResourceCount(accountId, ResourceType.template); } else { diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 2fd21334dca..339ef6f8933 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -351,7 +351,6 @@ INSERT INTO `cloud`.`sequence` (name, value) VALUES ('private_mac_address_seq', INSERT INTO `cloud`.`sequence` (name, value) VALUES ('storage_pool_seq', 200); INSERT INTO `cloud`.`sequence` (name, value) VALUES ('volume_seq', 1); INSERT INTO `cloud`.`sequence` (name, value) VALUES ('networks_seq', 200); -INSERT INTO `cloud`.`sequence` (name, value) VALUES ('snapshots_seq', 1); CREATE TABLE `cloud`.`volumes` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'Primary Key', @@ -398,13 +397,16 @@ CREATE TABLE `cloud`.`volumes` ( CREATE TABLE `cloud`.`snapshots` ( `id` bigint unsigned UNIQUE NOT NULL AUTO_INCREMENT COMMENT 'Primary Key', + `data_center_id` bigint unsigned NOT NULL, `account_id` bigint unsigned NOT NULL COMMENT 'owner. foreign key to account table', + `domain_id` bigint unsigned NOT NULL COMMENT 'the domain that the owner belongs to', `volume_id` bigint unsigned NOT NULL COMMENT 'volume it belongs to. foreign key to volume table', `status` varchar(32) COMMENT 'snapshot creation status', `path` varchar(255) COMMENT 'Path', `name` varchar(255) NOT NULL COMMENT 'snapshot name', `snapshot_type` int(4) NOT NULL COMMENT 'type of snapshot, e.g. manual, recurring', `type_description` varchar(25) COMMENT 'description of the type of snapshot, e.g. manual, recurring', + `size` bigint unsigned NOT NULL COMMENT 'original disk size of snapshot', `created` datetime COMMENT 'Date Created', `removed` datetime COMMENT 'Date removed. not null if removed', `backup_snap_id` varchar(255) COMMENT 'Back up uuid of the snapshot', @@ -1242,7 +1244,7 @@ CREATE TABLE `cloud`.`launch_permission` ( CREATE TABLE `cloud`.`snapshot_policy` ( `id` bigint unsigned NOT NULL auto_increment, - `volume_id` bigint unsigned NOT NULL unique, + `volume_id` bigint unsigned NOT NULL, `schedule` varchar(100) NOT NULL COMMENT 'schedule time of execution', `timezone` varchar(100) NOT NULL COMMENT 'the timezone in which the schedule time is specified', `interval` int(4) NOT NULL default 4 COMMENT 'backup schedule, e.g. hourly, daily, etc.', @@ -1260,11 +1262,12 @@ CREATE TABLE `cloud`.`snapshot_policy_ref` ( CREATE TABLE `cloud`.`snapshot_schedule` ( `id` bigint unsigned NOT NULL auto_increment, - `volume_id` bigint unsigned NOT NULL unique COMMENT 'The volume for which this snapshot is being taken', + `volume_id` bigint unsigned NOT NULL COMMENT 'The volume for which this snapshot is being taken', `policy_id` bigint unsigned NOT NULL COMMENT 'One of the policyIds for which this snapshot was taken', `scheduled_timestamp` datetime NOT NULL COMMENT 'Time at which the snapshot was scheduled for execution', `async_job_id` bigint unsigned COMMENT 'If this schedule is being executed, it is the id of the create aysnc_job. Before that it is null', `snapshot_id` bigint unsigned COMMENT 'If this schedule is being executed, then the corresponding snapshot has this id. Before that it is null', + UNIQUE (volume_id, policy_id), PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/setup/db/schema-21to22.sql b/setup/db/schema-21to22.sql index ed6acef2093..e74f430053c 100644 --- a/setup/db/schema-21to22.sql +++ b/setup/db/schema-21to22.sql @@ -2,7 +2,6 @@ -- Schema upgrade from 2.1 to 2.2; --; ALTER TABLE `cloud`.`template_host_ref` ADD COLUMN `physical_size` bigint unsigned NOT NULL DEFAULT 0; -ALTER TABLE `cloud`.`snapshots` MODIFY COLUMN `id` bigint unsigned UNIQUE NOT NULL; ALTER TABLE `cloud`.`vm_instance` DROP COLUMN `group`; ALTER TABLE `cloud`.`cluster` ADD COLUMN `guid` varchar(255) UNIQUE DEFAULT NULL; ALTER TABLE `cloud`.`cluster` ADD COLUMN `cluster_type` varchar(64) DEFAULT 'CloudManaged'; @@ -335,6 +334,10 @@ CREATE TABLE `cloud`.`upload` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; +ALTER TABLE `cloud`.`snapshots` ADD COLUMN `data_center_id` bigint unsigned NOT NULL; +ALTER TABLE `cloud`.`snapshots` ADD COLUMN `domain_id` bigint unsigned NOT NULL; +ALTER TABLE `cloud`.`snapshots` ADD COLUMN `size` bigint unsigned NOT NULL ; + ALTER TABLE `cloud`.`template_host_ref` ADD COLUMN `physical size` bigint unsigned DEFAULT 0; ALTER TABLE `cloud`.`console_proxy` MODIFY COLUMN `public_mac_address` varchar(17); @@ -518,4 +521,3 @@ CREATE TABLE `cloud`.`storage_pool_work` ( -- Insert stuff?; INSERT INTO `cloud`.`sequence` (name, value) VALUES ('volume_seq', (SELECT max(id) + 1 or 200 from volumes)); INSERT INTO `cloud`.`sequence` (name, value) VALUES ('networks_seq', 200); -INSERT INTO `cloud`.`sequence` (name, value) VALUES ('snapshots_seq', (SELECT max(id) + 1 or 200 from snapshots)); diff --git a/utils/src/com/cloud/utils/DateUtil.java b/utils/src/com/cloud/utils/DateUtil.java index d9bbad4592b..67a6536e2a3 100644 --- a/utils/src/com/cloud/utils/DateUtil.java +++ b/utils/src/com/cloud/utils/DateUtil.java @@ -91,17 +91,7 @@ public class DateUtil { DAILY, WEEKLY, MONTHLY; - - private int max = 8; - - public void setMax(int max) { - this.max = max; - } - - public int getMax() { - return max; - } - + boolean equals(String intervalType) { return super.toString().equalsIgnoreCase(intervalType); } diff --git a/utils/src/com/cloud/utils/db/GenericDao.java b/utils/src/com/cloud/utils/db/GenericDao.java index f4da5abac6a..9ddf0ee5da7 100755 --- a/utils/src/com/cloud/utils/db/GenericDao.java +++ b/utils/src/com/cloud/utils/db/GenericDao.java @@ -228,5 +228,11 @@ public interface GenericDao { boolean configure(String name, Map params) throws ConfigurationException; List customSearch(SearchCriteria sc, Filter filter); + + boolean lockInLockTable(String id); + + boolean lockInLockTable(String id, int seconds); + + boolean unlockFromLockTable(String id); } \ No newline at end of file diff --git a/utils/src/com/cloud/utils/db/GenericDaoBase.java b/utils/src/com/cloud/utils/db/GenericDaoBase.java index 79a8e0979da..4c9f349a86b 100755 --- a/utils/src/com/cloud/utils/db/GenericDaoBase.java +++ b/utils/src/com/cloud/utils/db/GenericDaoBase.java @@ -923,6 +923,23 @@ public abstract class GenericDaoBase implements Gene final Transaction txn = Transaction.currentTxn(); return txn.release(_table + id); } + + @Override @DB(txn=false) + public boolean lockInLockTable(final String id) { + return lockInLockTable(id, _timeoutSeconds); + } + + @Override + public boolean lockInLockTable(final String id, int seconds) { + Transaction txn = Transaction.currentTxn(); + return txn.lock(_table + id, seconds); + } + + @Override + public boolean unlockFromLockTable(final String id) { + final Transaction txn = Transaction.currentTxn(); + return txn.release(_table + id); + } @Override @DB(txn=false) public List listAllIncludingRemoved() {