/*************************************************************************
* Copyright 2009-2013 Eucalyptus Systems, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
* Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta
* CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need
* additional information or have any questions.
************************************************************************/
package com.eucalyptus.autoscaling.common.internal.groups;
import static com.eucalyptus.autoscaling.common.AutoScalingMetadata.TerminationPolicyTypeMetadata;
import static com.eucalyptus.autoscaling.common.internal.instances.AutoScalingInstances.launchConfigurationName;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import com.eucalyptus.auth.principal.Principals;
import com.eucalyptus.autoscaling.common.internal.instances.AutoScalingInstanceCoreView;
import com.eucalyptus.util.CollectionUtils;
import com.eucalyptus.auth.principal.OwnerFullName;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
/**
*
*/
public enum TerminationPolicyType implements TerminationPolicyTypeMetadata {
OldestInstance {
@Override
public List<AutoScalingInstanceCoreView> selectForTermination( final List<AutoScalingInstanceCoreView> instances ) {
final Date oldest = dateOfOldestInstance( instances );
return filterByPropertyEquality( instances, oldest, InstanceCreatedDate.INSTANCE );
}
},
OldestLaunchConfiguration {
@Override
public List<AutoScalingInstanceCoreView> selectForTermination( final List<AutoScalingInstanceCoreView> instances ) {
final Date oldest = dateOfOldestInstance( instances );
final AutoScalingInstanceCoreView instanceWithOldestLaunchConfiguration =
Iterables.find(
instances,
Predicates.compose( Predicates.equalTo( oldest ), InstanceCreatedDate.INSTANCE ),
null
);
final String oldestLaunchConfiguration = instanceWithOldestLaunchConfiguration == null ?
null :
instanceWithOldestLaunchConfiguration.getLaunchConfigurationName();
return filterByPropertyEquality( instances, oldestLaunchConfiguration, launchConfigurationName( ) );
}
},
NewestInstance {
@Override
public List<AutoScalingInstanceCoreView> selectForTermination( final List<AutoScalingInstanceCoreView> instances ) {
final Date newest = dateOfNewestInstance( instances );
return filterByPropertyEquality( instances, newest, InstanceCreatedDate.INSTANCE );
}
},
ClosestToNextInstanceHour {
@Override
public List<AutoScalingInstanceCoreView> selectForTermination( final List<AutoScalingInstanceCoreView> instances ) {
final Function<? super AutoScalingInstanceCoreView,Integer> secondsToInstanceHourFunction =
Functions.compose( DateToTimeUntilNextHour.INSTANCE, InstanceCreatedDate.INSTANCE );
final Integer secondsToInstanceHour = CollectionUtils.reduce(
Iterables.transform( instances, secondsToInstanceHourFunction ),
Integer.MAX_VALUE,
CollectionUtils.comparator( Ordering.<Integer>natural() ) );
return filterByPropertyEquality( instances, secondsToInstanceHour, secondsToInstanceHourFunction );
}
},
Default {
@Override
public List<AutoScalingInstanceCoreView> selectForTermination( final List<AutoScalingInstanceCoreView> instances ) {
final List<AutoScalingInstanceCoreView> oldestList = OldestLaunchConfiguration.selectForTermination( instances );
final List<AutoScalingInstanceCoreView> closestToInstanceHour = ClosestToNextInstanceHour.selectForTermination( oldestList );
final List<AutoScalingInstanceCoreView> result;
if ( closestToInstanceHour.size() == 1 ) {
result = closestToInstanceHour;
} else if ( closestToInstanceHour.isEmpty() ) {
result = Lists.newArrayList();
} else {
Collections.shuffle( closestToInstanceHour );
result = closestToInstanceHour.subList( 0, 1 );
}
return result;
}
};
@Override
public String getDisplayName() {
return name();
}
@Override
public OwnerFullName getOwner() {
return Principals.systemFullName();
}
public abstract List<AutoScalingInstanceCoreView> selectForTermination( List<AutoScalingInstanceCoreView> instances );
/**
* Select an instance for termination from the given list.
*
* @param terminationPolicyTypes The ordered list of termination policies to use.
* @param instances The non empty list of instances
* @return The instance selected for termination
* @throws IllegalArgumentException if passed an empty list
*/
public static AutoScalingInstanceCoreView selectForTermination( final Collection<TerminationPolicyType> terminationPolicyTypes,
final List<AutoScalingInstanceCoreView> instances ) {
if ( instances.isEmpty() ) throw new IllegalArgumentException( "No instances provided" );
List<AutoScalingInstanceCoreView> currentList = instances;
for ( TerminationPolicyType terminationPolicyType :
Iterables.concat( terminationPolicyTypes, Collections.singleton( TerminationPolicyType.Default ) ) ) {
if ( currentList.size() == 1 ) break;
currentList = terminationPolicyType.selectForTermination( currentList );
}
return currentList.get( 0 );
}
private static <T> List<AutoScalingInstanceCoreView> filterByPropertyEquality( final List<AutoScalingInstanceCoreView> instances,
final T target,
final Function<? super AutoScalingInstanceCoreView,T> propertyFunction ) {
return Lists.newArrayList( Iterables.filter(
instances,
Predicates.compose( Predicates.equalTo( target ), propertyFunction ) ) );
}
private static Date dateOfOldestInstance( final List<AutoScalingInstanceCoreView> instances ) {
return dateOfInstance( instances, new Date( Long.MAX_VALUE ), Ordering.<Date>natural() );
}
private static Date dateOfNewestInstance( final List<AutoScalingInstanceCoreView> instances ) {
return dateOfInstance( instances, new Date( 0 ), Ordering.<Date>natural().reverse() );
}
private static Date dateOfInstance( final List<AutoScalingInstanceCoreView> instances,
final Date initialDate,
final Comparator<Date> comparator ) {
return CollectionUtils.reduce(
Iterables.transform( instances, InstanceCreatedDate.INSTANCE ),
initialDate,
CollectionUtils.comparator( comparator ) );
}
private enum DateToTimeUntilNextHour implements Function<Date,Integer> {
INSTANCE;
@Override
public Integer apply( final Date date ) {
long timeInHour = date.getTime() % TimeUnit.HOURS.toMillis( 1 );
return (int)(( TimeUnit.HOURS.toMillis( 1 ) - timeInHour ) / 1000L);
}
}
private enum InstanceCreatedDate implements Function<AutoScalingInstanceCoreView,Date> {
INSTANCE;
@Override
public Date apply( final AutoScalingInstanceCoreView instance ) {
return new Date( instance.getCreationTimestamp( ) );
}
}
}