diff --git a/clc/modules/compute-backend/src/main/java/com/eucalyptus/blockstorage/VolumeUpdateEventListener.java b/clc/modules/compute-backend/src/main/java/com/eucalyptus/blockstorage/VolumeUpdateEventListener.java index 134e0850a66..d301319b7c6 100644 --- a/clc/modules/compute-backend/src/main/java/com/eucalyptus/blockstorage/VolumeUpdateEventListener.java +++ b/clc/modules/compute-backend/src/main/java/com/eucalyptus/blockstorage/VolumeUpdateEventListener.java @@ -183,6 +183,10 @@ public Volume apply( final String input ) { size = Integer.parseInt( storageVolume.getSize( ) ); } if ( newState.isPresent( ) ) { + if ( State.ANNIHILATED == newState.get( ) && isDeleteExpired( volumeToUpdate ) ) { + Entities.delete( volumeToUpdate ); + return volumeToUpdate; + } volumeState = newState.get( ); } volumeToUpdate.setState( volumeState ); @@ -197,10 +201,6 @@ public Volume apply( final String input ) { LOG.error( ex ); Logs.extreme( ).error( ex, ex ); } - //TODO:GRZE: expire deleted/failed volumes in the future. - // if ( State.ANNIHILATED.equals( v.getState( ) ) && State.ANNIHILATED.equals( v.getState( ) ) && v.lastUpdateMillis( ) > VOLUME_DELETE_TIMEOUT ) { - // Entities.delete( v ); - // } buf.append( " Resulting new-state: [" ).append( volumeToUpdate.getState( ) ).append("]"); LOG.debug( buf.toString( ) ); return volumeToUpdate; @@ -233,6 +233,7 @@ public Volume apply( final String input ) { } if ( volume.getSize( ) <= 0 || + isDeleteExpired( volume ) || ( newState.isPresent( ) && newState.get( ) != volume.getState( ) ) ) { Entities.asTransaction( Volume.class, updateVolume ).apply( volume.getDisplayName( ) ); } else { @@ -240,6 +241,11 @@ public Volume apply( final String input ) { } } + static boolean isDeleteExpired( final Volume volume ) { + return State.ANNIHILATED == volume.getState( ) + && volume.getSplitTime( TimeUnit.MINUTES ) > Volumes.DELETED_TIME; + } + static Optional calculateState( final Volume volumeToUpdate, final String storageStatus ) { Optional state = Optional.of( volumeToUpdate.getState( ) ); if ( storageStatus != null ) { diff --git a/clc/modules/compute-backend/src/main/java/com/eucalyptus/blockstorage/Volumes.java b/clc/modules/compute-backend/src/main/java/com/eucalyptus/blockstorage/Volumes.java index 8ad70a703b9..e638f8c196a 100644 --- a/clc/modules/compute-backend/src/main/java/com/eucalyptus/blockstorage/Volumes.java +++ b/clc/modules/compute-backend/src/main/java/com/eucalyptus/blockstorage/Volumes.java @@ -67,6 +67,8 @@ import com.eucalyptus.compute.common.internal.blockstorage.Volume; import com.eucalyptus.compute.common.internal.blockstorage.VolumeTag; import com.eucalyptus.compute.common.internal.identifier.ResourceIdentifiers; +import com.eucalyptus.configurable.ConfigurableClass; +import com.eucalyptus.configurable.ConfigurableField; import com.eucalyptus.entities.Entities; import com.eucalyptus.entities.TransactionException; import com.eucalyptus.entities.TransactionResource; @@ -92,8 +94,15 @@ import edu.ucsb.eucalyptus.cloud.VolumeSizeExceededException; +@ConfigurableClass( root = "cloud.volumes", + description = "Parameters controlling storage volumes." ) public class Volumes { - private static Logger LOG = Logger.getLogger( Volumes.class ); + private static final Logger LOG = Logger.getLogger( Volumes.class ); + + @ConfigurableField( description = "Amount of time (in minutes) that a deleted volume will continue to be reported.", + initial = "60" ) + public static Integer DELETED_TIME = 60; + @QuantityMetricFunction( VolumeMetadata.class ) public enum CountVolumes implements Function { diff --git a/clc/modules/compute-common/src/main/java/com/eucalyptus/compute/common/internal/blockstorage/Volume.java b/clc/modules/compute-common/src/main/java/com/eucalyptus/compute/common/internal/blockstorage/Volume.java index d8c592d59d0..0fbadeb7006 100644 --- a/clc/modules/compute-common/src/main/java/com/eucalyptus/compute/common/internal/blockstorage/Volume.java +++ b/clc/modules/compute-common/src/main/java/com/eucalyptus/compute/common/internal/blockstorage/Volume.java @@ -41,6 +41,7 @@ import java.util.Collection; import java.util.Date; +import java.util.concurrent.TimeUnit; import javax.annotation.Nullable; import javax.persistence.CascadeType; @@ -167,7 +168,13 @@ public String mapState( ) { return "unavailable"; } } - + + public synchronized long getSplitTime( final TimeUnit units ) { + final long time = System.currentTimeMillis( ); + final long split = time - super.getLastUpdateTimestamp( ).getTime( ); + return units.convert( split, TimeUnit.MILLISECONDS ); + } + public com.eucalyptus.compute.common.Volume morph( final com.eucalyptus.compute.common.Volume vol ) { vol.setAvailabilityZone( this.getPartition( ) ); vol.setCreateTime( this.getCreationTimestamp( ) ); diff --git a/clc/modules/compute-service/src/main/java/com/eucalyptus/compute/service/ComputeService.java b/clc/modules/compute-service/src/main/java/com/eucalyptus/compute/service/ComputeService.java index 218fdff79b5..735055ccba6 100644 --- a/clc/modules/compute-service/src/main/java/com/eucalyptus/compute/service/ComputeService.java +++ b/clc/modules/compute-service/src/main/java/com/eucalyptus/compute/service/ComputeService.java @@ -845,7 +845,6 @@ public ArrayList apply( final Set // build response volumes for ( final Volume foundVol : filteredVolumes ) { if ( State.ANNIHILATED.equals( foundVol.getState( ) ) ) { - Entities.delete( foundVol ); if ( filterPredicate.apply( foundVol ) ) { replyVolumes.add( foundVol.morph( new com.eucalyptus.compute.common.Volume( ) ) ); } @@ -923,9 +922,6 @@ public ArrayList apply( final Set input ) { volumes, Predicates.and( new TrackingPredicate<>( volumeIds ), requestedAndAccessible ) ); for ( final Volume foundVol : filteredVolumes ) { - if ( State.ANNIHILATED.equals( foundVol.getState( ) ) ) { - Entities.delete( foundVol ); - } replyVolumes.add( volumeTransform.apply( foundVol ) ); } return replyVolumes;