/*************************************************************************
* 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.config;
import static com.eucalyptus.autoscaling.activities.ActivityManager.ActivityTask;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.util.EnumSet;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.log4j.Logger;
import com.eucalyptus.autoscaling.common.internal.groups.ScalingProcessType;
import com.eucalyptus.configurable.ConfigurableClass;
import com.eucalyptus.configurable.ConfigurableField;
import com.eucalyptus.configurable.ConfigurableProperty;
import com.eucalyptus.configurable.ConfigurablePropertyException;
import com.eucalyptus.configurable.PropertyChangeListener;
import com.eucalyptus.configurable.PropertyChangeListeners;
import com.eucalyptus.util.FUtils;
import com.eucalyptus.util.Intervals;
import com.google.common.base.Predicates;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
/**
*
*/
@ConfigurableClass(root = "autoscaling", description = "Parameters controlling auto scaling")
public class AutoScalingConfiguration {
private static final Logger logger = Logger.getLogger( AutoScalingConfiguration.class );
@ConfigurableField( initial = "5m", description = "Timeout for a scaling activity.", changeListener = AutoScalingIntervalPropertyChangeListener.class )
public static volatile String activityTimeout = "5m";
@ConfigurableField( initial = "42d", description = "Expiry age for scaling activities. Older activities are deleted.", changeListener = AutoScalingIntervalPropertyChangeListener.class )
public static volatile String activityExpiry = "42d";
@ConfigurableField( initial = "20", description = "Maximum instances to launch at one time." )
public static volatile int maxLaunchIncrement = 20;
@ConfigurableField( initial = "5", description = "Number of times to attempt load balancer registration for each instance." )
public static volatile int maxRegistrationRetries = 5;
@ConfigurableField( initial = "5m", description = "Time after which an unavailable zone should be treated as failed", changeListener=AutoScalingIntervalPropertyChangeListener.class )
public static volatile String zoneFailureThreshold = "5m";
@ConfigurableField( initial = "1d", description = "Timeout for administrative suspension of scaling activities for a group.", changeListener=AutoScalingIntervalPropertyChangeListener.class )
public static volatile String suspensionTimeout = "1d";
@ConfigurableField( initial = "15", description = "Minimum launch attempts for administrative suspension of scaling activities for a group." )
public static volatile int suspensionLaunchAttemptsThreshold = 15;
@ConfigurableField( initial = "", description = "Globally suspended scaling processes.", changeListener = AutoScalingSuspendedProcessesPropertyChangeListener.class )
public static volatile String suspendedProcesses = "";
@ConfigurableField( initial = "", description = "Suspended scaling tasks.", changeListener = AutoScalingSuspendedTasksPropertyChangeListener.class )
public static volatile String suspendedTasks = "";
@ConfigurableField( initial = "5m", description = "Timeout for termination of untracked auto scaling instances." )
public static volatile String untrackedInstanceTimeout = "5m";
@ConfigurableField( initial = "15m", description = "Timeout for a pending instance.", changeListener = AutoScalingIntervalPropertyChangeListener.class )
public static volatile String pendingInstanceTimeout = "15m";
@ConfigurableField( initial = "15m", description = "Maximum backoff period for failing activities.", changeListener = AutoScalingIntervalPropertyChangeListener.class )
public static volatile String activityMaxBackoff = "15m";
@ConfigurableField( initial = "9s", description = "Initial backoff period for failing activities.", changeListener = AutoScalingIntervalPropertyChangeListener.class )
public static volatile String activityInitialBackoff = "9s";
@ConfigurableField( initial = "50", description = "Maximum number of user defined tags for a group.", changeListener = PropertyChangeListeners.IsNonNegativeInteger.class )
public static volatile int maxTags = 50;
private static AtomicLong activityTimeoutMillis = new AtomicLong( Intervals.parse( activityTimeout, TimeUnit.MINUTES.toMillis( 5 ) ) );
private static AtomicLong activityExpiryMillis = new AtomicLong( Intervals.parse( activityExpiry, TimeUnit.DAYS.toMillis( 42 ) ) );
private static AtomicLong zoneFailureThresholdMillis = new AtomicLong( Intervals.parse( zoneFailureThreshold, TimeUnit.MINUTES.toMillis( 5 ) ) );
private static AtomicLong suspensionTimeoutMillis = new AtomicLong( Intervals.parse( suspensionTimeout, TimeUnit.DAYS.toMillis( 1 ) ) );
private static AtomicLong untrackedInstanceTimeoutMillis = new AtomicLong( Intervals.parse( untrackedInstanceTimeout, TimeUnit.MINUTES.toMillis( 5 ) ) );
private static AtomicLong pendingInstanceTimeoutMillis = new AtomicLong( Intervals.parse( pendingInstanceTimeout, TimeUnit.MINUTES.toMillis( 15 ) ) );
private static AtomicLong activityMaxBackoffMillis = new AtomicLong( Intervals.parse( activityMaxBackoff, TimeUnit.MINUTES.toMillis( 15 ) ) );
private static AtomicLong activityInitialBackoffMillis = new AtomicLong( Intervals.parse( activityInitialBackoff, TimeUnit.SECONDS.toMillis( 9 ) ) );
private static AtomicReference<EnumSet<ScalingProcessType>> suspendedProcessesSet = new AtomicReference<EnumSet<ScalingProcessType>>( toEnumSet( ScalingProcessType.class, suspendedProcesses ) );
private static AtomicReference<EnumSet<ActivityTask>> suspendedTasksSet = new AtomicReference<EnumSet<ActivityTask>>( toEnumSet( ActivityTask.class, suspendedTasks ) );
public static int getMaxLaunchIncrement() {
return maxLaunchIncrement;
}
public static int getMaxRegistrationRetries() {
return maxRegistrationRetries;
}
public static int getMaxTags() {
return maxTags;
}
public static int getSuspensionLaunchAttemptsThreshold() {
return suspensionLaunchAttemptsThreshold;
}
public static long getActivityTimeoutMillis() {
return activityTimeoutMillis.get();
}
public static long getActivityExpiryMillis() {
return activityExpiryMillis.get();
}
public static long getZoneFailureThresholdMillis() {
return zoneFailureThresholdMillis.get();
}
public static long getSuspensionTimeoutMillis() {
return suspensionTimeoutMillis.get();
}
public static long getUntrackedInstanceTimeoutMillis() {
return untrackedInstanceTimeoutMillis.get();
}
public static long getPendingInstanceTimeoutMillis() {
return pendingInstanceTimeoutMillis.get();
}
public static long getActivityMaxBackoffMillis() {
return activityMaxBackoffMillis.get();
}
public static long getActivityInitialBackoffMillis() {
return activityInitialBackoffMillis.get();
}
public static EnumSet<ScalingProcessType> getSuspendedProcesses() {
return suspendedProcessesSet.get();
}
public static EnumSet<ActivityTask> getSuspendedTasks() {
return suspendedTasksSet.get();
}
private static <E extends Enum<E>> EnumSet<E> toEnumSet( final Class<E> enumClass,
final String text ) {
final List<E> values = Lists.newArrayList( Iterables.filter(
Iterables.transform(
Splitter.on( "," ).omitEmptyStrings().trimResults().split( text ),
FUtils.valueOfFunction( enumClass ) ),
Predicates.notNull() ) );
return values.isEmpty() ?
EnumSet.noneOf( enumClass ) :
EnumSet.copyOf( values );
}
public static final class AutoScalingIntervalPropertyChangeListener implements PropertyChangeListener {
@Override
public void fireChange( final ConfigurableProperty configurableProperty,
final Object newValue ) throws ConfigurablePropertyException {
try {
final String fieldName = configurableProperty.getField().getName() + "Millis";
final Field field = AutoScalingConfiguration.class.getDeclaredField( fieldName );
final long defaultValue = Intervals.parse( configurableProperty.getDefaultValue() );
final long value = Intervals.parse( String.valueOf( newValue ), defaultValue );
field.setAccessible( true );
logger.info( "Auto scaling configuration updated " + field.getName() + ": " + value + "ms" );
((AtomicLong)field.get( null )).set( value );
} catch ( NoSuchFieldException e ) {
logger.error( e, e );
} catch ( ParseException e ) {
logger.error( e, e );
} catch ( IllegalAccessException e ) {
logger.error( e, e );
}
}
}
public static final class AutoScalingSuspendedProcessesPropertyChangeListener implements PropertyChangeListener {
@Override
public void fireChange( final ConfigurableProperty configurableProperty,
final Object newValue ) throws ConfigurablePropertyException {
final EnumSet<ScalingProcessType> scalingProcessTypes = toEnumSet( ScalingProcessType.class, String.valueOf( newValue ) );
logger.info( "Suspended auto scaling processes updated: " + scalingProcessTypes );
suspendedProcessesSet.set( scalingProcessTypes );
}
}
public static final class AutoScalingSuspendedTasksPropertyChangeListener implements PropertyChangeListener {
@Override
public void fireChange( final ConfigurableProperty configurableProperty,
final Object newValue ) throws ConfigurablePropertyException {
final EnumSet<ActivityTask> activityTasks = toEnumSet( ActivityTask.class, String.valueOf( newValue ) );
logger.info( "Suspended auto scaling activity tasks updated: " + activityTasks );
suspendedTasksSet.set( activityTasks );
}
}
}