Skip to content

Commit

Permalink
Auto scaling policy management - EUCA-4849
Browse files Browse the repository at this point in the history
A "policies" package is added with scaling policy persistent objects
and a ScalingPolicies class providing access.

The AutoScalingService is updated to support create, describe, update
and delete for scaling policies as well as policy execution and describe
for adjustment types. Associated messages are updated with convenience
methods and Query API binding annotations. AutoScalingMetadata classes
are created for new public types.

Added a QuantityMetricFunction and ScalingPolicyNumberQuotaKey for
scaling policy quota support.

EUCA-4849
  • Loading branch information
sjones4 committed Jan 30, 2013
1 parent 4643212 commit 0217eee
Show file tree
Hide file tree
Showing 13 changed files with 1,029 additions and 26 deletions.
Expand Up @@ -101,6 +101,8 @@ public class LoadBalancerNames extends EucalyptusData {
}
public class PolicyNames extends EucalyptusData {
public PolicyNames() { }
@HttpParameterMapping(parameter="member")
@HttpEmbedded(multiple=true)
ArrayList<String> member = new ArrayList<String>()
}
public class DescribeTerminationPolicyTypesType extends AutoScalingMessage {
Expand Down Expand Up @@ -678,7 +680,7 @@ public class BlockDeviceMappingType extends EucalyptusData {
}
public class ScalingPolicies extends EucalyptusData {
public ScalingPolicies() { }
ArrayList<ScalingPolicy> member = new ArrayList<ScalingPolicy>()
ArrayList<ScalingPolicyType> member = new ArrayList<ScalingPolicyType>()
}
public class ResponseMetadata extends EucalyptusData {
String requestId
Expand All @@ -695,7 +697,7 @@ public class DescribeLaunchConfigurationsResult extends EucalyptusData {
public DescribeLaunchConfigurationsResult() { }
}
public class DescribePoliciesResult extends EucalyptusData {
ScalingPolicies scalingPolicies
ScalingPolicies scalingPolicies = new ScalingPolicies()
String nextToken
public DescribePoliciesResult() { }
}
Expand Down Expand Up @@ -763,7 +765,7 @@ public class DescribeScalingActivitiesResponseType extends AutoScalingMessage {
DescribeScalingActivitiesResult describeScalingActivitiesResult = new DescribeScalingActivitiesResult()
ResponseMetadata responseMetadata = new ResponseMetadata()
}
public class ScalingPolicy extends AutoScalingMessage {
public class ScalingPolicyType extends AutoScalingMessage {
String autoScalingGroupName
String policyName
Integer scalingAdjustment
Expand All @@ -772,7 +774,7 @@ public class ScalingPolicy extends AutoScalingMessage {
String policyARN
Alarms alarms
Integer minAdjustmentStep
public ScalingPolicy() { }
public ScalingPolicyType() { }
}
public class AutoScalingGroupNames extends EucalyptusData {
public AutoScalingGroupNames() { }
Expand All @@ -799,10 +801,18 @@ public class Activities extends AutoScalingMessage {
}
public class DescribePoliciesType extends AutoScalingMessage {
String autoScalingGroupName
@HttpEmbedded
PolicyNames policyNames
String nextToken
Integer maxRecords
public DescribePoliciesType() { }
public List<String> policyNames() {
List<String> names = Lists.newArrayList()
if ( policyNames != null ) {
names = policyNames.getMember()
}
return names
}
}
public class PutScalingPolicyResult extends EucalyptusData {
String policyARN
Expand Down Expand Up @@ -867,6 +877,10 @@ public class ProcessNames extends EucalyptusData {
public class DescribeAdjustmentTypesResult extends EucalyptusData {
AdjustmentTypes adjustmentTypes
public DescribeAdjustmentTypesResult() { }
public void setAdjustmentTypes( Collection<String> values ) {
adjustmentTypes = new AdjustmentTypes( member: values.collect {
value -> new AdjustmentType( adjustmentType: value ) } )
}
}
public class DescribeScalingProcessTypesResult extends EucalyptusData {
Processes processes
Expand Down
Expand Up @@ -38,4 +38,10 @@ public interface AutoScalingGroupMetadata extends AutoScalingMetadata {}

@PolicyResourceType( "terminationpolicytype" )
public interface TerminationPolicyTypeMetadata extends AutoScalingMetadata {}

@PolicyResourceType( "adjustmenttype" )
public interface AdjustmentTypeMetadata extends AutoScalingMetadata {}

@PolicyResourceType( "scalingpolicy" )
public interface ScalingPolicyMetadata extends AutoScalingMetadata {}
}
Expand Up @@ -613,7 +613,7 @@
<value name="Progress" field="progress" usage="optional"/>
<value name="Details" field="details" usage="optional"/>
</mapping>
<mapping class="com.eucalyptus.autoscaling.common.ScalingPolicy" abstract="true">
<mapping class="com.eucalyptus.autoscaling.common.ScalingPolicyType" abstract="true">
<structure map-as="com.eucalyptus.autoscaling.common.AutoScalingMessage"/>
<value name="AutoScalingGroupName" field="autoScalingGroupName" usage="optional"/>
<value name="PolicyName" field="policyName" usage="optional"/>
Expand Down Expand Up @@ -742,7 +742,7 @@
</mapping>
<mapping class="com.eucalyptus.autoscaling.common.ScalingPolicies" abstract="true">
<collection field="member">
<structure name="member" type="com.eucalyptus.autoscaling.common.ScalingPolicy"/>
<structure name="member" type="com.eucalyptus.autoscaling.common.ScalingPolicyType"/>
</collection>
</mapping>
<mapping class="com.eucalyptus.autoscaling.common.Activities" abstract="true">
Expand Down
Expand Up @@ -21,7 +21,7 @@

import static com.eucalyptus.autoscaling.common.AutoScalingMetadata.AutoScalingGroupMetadata;
import static com.eucalyptus.autoscaling.common.AutoScalingMetadata.LaunchConfigurationMetadata;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import org.apache.log4j.Logger;
import org.hibernate.exception.ConstraintViolationException;
Expand Down Expand Up @@ -89,6 +89,7 @@
import com.eucalyptus.autoscaling.common.PutScheduledUpdateGroupActionType;
import com.eucalyptus.autoscaling.common.ResumeProcessesResponseType;
import com.eucalyptus.autoscaling.common.ResumeProcessesType;
import com.eucalyptus.autoscaling.common.ScalingPolicyType;
import com.eucalyptus.autoscaling.common.SetDesiredCapacityResponseType;
import com.eucalyptus.autoscaling.common.SetDesiredCapacityType;
import com.eucalyptus.autoscaling.common.SetInstanceHealthResponseType;
Expand All @@ -107,9 +108,14 @@
import com.eucalyptus.autoscaling.groups.HealthCheckType;
import com.eucalyptus.autoscaling.groups.PersistenceAutoScalingGroups;
import com.eucalyptus.autoscaling.groups.TerminationPolicyType;
import com.eucalyptus.autoscaling.policies.AdjustmentType;
import com.eucalyptus.autoscaling.policies.PersistenceScalingPolicies;
import com.eucalyptus.autoscaling.policies.ScalingPolicies;
import com.eucalyptus.autoscaling.policies.ScalingPolicy;
import com.eucalyptus.context.Context;
import com.eucalyptus.context.Contexts;
import com.eucalyptus.util.Callback;
import com.eucalyptus.util.CollectionUtils;
import com.eucalyptus.util.EucalyptusCloudException;
import com.eucalyptus.util.Exceptions;
import com.eucalyptus.util.Numbers;
Expand All @@ -118,6 +124,7 @@
import com.eucalyptus.util.Strings;
import com.eucalyptus.util.TypeMappers;
import com.google.common.base.Enums;
import com.google.common.base.Objects;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Supplier;
Expand All @@ -129,17 +136,21 @@ public class AutoScalingService {
private static final Logger logger = Logger.getLogger( AutoScalingService.class );
private final LaunchConfigurations launchConfigurations;
private final AutoScalingGroups autoScalingGroups;
private final ScalingPolicies scalingPolicies;

public AutoScalingService() {
this(
new PersistenceLaunchConfigurations( ),
new PersistenceAutoScalingGroups( ) );
new PersistenceAutoScalingGroups( ),
new PersistenceScalingPolicies( ) );
}

protected AutoScalingService( final LaunchConfigurations launchConfigurations,
final AutoScalingGroups autoScalingGroups ) {
final AutoScalingGroups autoScalingGroups,
final ScalingPolicies scalingPolicies ) {
this.launchConfigurations = launchConfigurations;
this.autoScalingGroups = autoScalingGroups;
this.scalingPolicies = scalingPolicies;
}

public DescribeAutoScalingGroupsResponseType describeAutoScalingGroups( final DescribeAutoScalingGroupsType request ) throws EucalyptusCloudException {
Expand Down Expand Up @@ -196,8 +207,34 @@ public DeleteLaunchConfigurationResponseType deleteLaunchConfiguration( final De
return reply;
}

public DescribePoliciesResponseType describePolicies(DescribePoliciesType request) throws EucalyptusCloudException {
DescribePoliciesResponseType reply = request.getReply( );
public DescribePoliciesResponseType describePolicies(final DescribePoliciesType request) throws EucalyptusCloudException {
final DescribePoliciesResponseType reply = request.getReply( );

//TODO:STEVE: MaxRecords / NextToken support for DescribePolicies

final Context ctx = Contexts.lookup( );
final boolean showAll = request.policyNames().remove( "verbose" );
final OwnerFullName ownerFullName = ctx.hasAdministrativePrivileges( ) && showAll ?
null :
ctx.getUserFullName( ).asAccountFullName( );

final Predicate<ScalingPolicy> requestedAndAccessible =
Predicates.and(
AutoScalingMetadatas.filterPrivilegesById( request.policyNames() ),
AutoScalingMetadatas.filterByProperty(
CollectionUtils.<String>listUnit().apply(request.getAutoScalingGroupName()),
ScalingPolicies.toGroupName() )
);

try {
final List<ScalingPolicyType> results = reply.getDescribePoliciesResult().getScalingPolicies().getMember();
for ( final ScalingPolicy scalingPolicy : scalingPolicies.list( ownerFullName, requestedAndAccessible ) ) {
results.add( TypeMappers.transform( scalingPolicy, ScalingPolicyType.class ) );
}
} catch ( Exception e ) {
handleException( e );
}

return reply;
}

Expand Down Expand Up @@ -268,7 +305,7 @@ public DescribeTerminationPolicyTypesResponseType describeTerminationPolicyTypes

final List<String> policies = reply.getDescribeTerminationPolicyTypesResult().getTerminationPolicyTypes().getMember();
policies.addAll( Collections2.transform(
Collections2.filter( Arrays.asList( TerminationPolicyType.values() ), RestrictedTypes.filterPrivilegedWithoutOwner() ),
Collections2.filter( EnumSet.allOf( TerminationPolicyType.class ), RestrictedTypes.filterPrivilegedWithoutOwner() ),
Strings.toStringFunction() ) );

return reply;
Expand All @@ -279,8 +316,40 @@ public DescribeTagsResponseType describeTags(DescribeTagsType request) throws Eu
return reply;
}

public ExecutePolicyResponseType executePolicy(ExecutePolicyType request) throws EucalyptusCloudException {
ExecutePolicyResponseType reply = request.getReply( );
public ExecutePolicyResponseType executePolicy(final ExecutePolicyType request) throws EucalyptusCloudException {
final ExecutePolicyResponseType reply = request.getReply( );

//TODO:STEVE: cooldown support

final Context ctx = Contexts.lookup( );
final AccountFullName accountFullName = ctx.getUserFullName( ).asAccountFullName( );
try {
final ScalingPolicy scalingPolicy;
try {
scalingPolicy = scalingPolicies.lookup(
accountFullName,
request.getAutoScalingGroupName(),
request.getPolicyName() );
} catch ( AutoScalingMetadataNotFoundException e ) {
throw new InvalidParameterValueException( "Scaling policy not found: " + request.getPolicyName() );
}

autoScalingGroups.update( accountFullName, request.getAutoScalingGroupName(), new Callback<AutoScalingGroup>(){
@Override
public void fire( final AutoScalingGroup autoScalingGroup ) {
autoScalingGroup.setDesiredCapacity( scalingPolicy.getAdjustmentType().adjustCapacity(
autoScalingGroup.getDesiredCapacity(), //TODO:STEVE: should be actual capacity ...
scalingPolicy.getScalingAdjustment(),
Objects.firstNonNull( scalingPolicy.getMinAdjustmentStep(), 0),
Objects.firstNonNull( autoScalingGroup.getMinSize(), 0 ),
Objects.firstNonNull( autoScalingGroup.getMaxSize(), Integer.MAX_VALUE )
) );
}
} );
} catch( Exception e ) {
handleException( e );
}

return reply;
}

Expand All @@ -289,8 +358,75 @@ public DeleteTagsResponseType deleteTags(DeleteTagsType request) throws Eucalypt
return reply;
}

public PutScalingPolicyResponseType putScalingPolicy(PutScalingPolicyType request) throws EucalyptusCloudException {
PutScalingPolicyResponseType reply = request.getReply( );
public PutScalingPolicyResponseType putScalingPolicy(final PutScalingPolicyType request) throws EucalyptusCloudException {
final PutScalingPolicyResponseType reply = request.getReply( );

final Context ctx = Contexts.lookup( );
final AccountFullName accountFullName = ctx.getUserFullName( ).asAccountFullName();
try {
// Try update
final ScalingPolicy scalingPolicy = scalingPolicies.update(
accountFullName,
request.getAutoScalingGroupName(),
request.getPolicyName(), new Callback<ScalingPolicy>() {
@Override
public void fire( final ScalingPolicy scalingPolicy ) {
if ( RestrictedTypes.filterPrivileged().apply( scalingPolicy ) ) {
//TODO:STEVE: input validation
// You will get a ValidationError if you use MinAdjustmentStep on a policy with an AdjustmentType other than PercentChangeInCapacity.
if ( request.getAdjustmentType() != null )
scalingPolicy.setAdjustmentType(
Enums.valueOfFunction( AdjustmentType.class ).apply( request.getAdjustmentType() ) );
if ( request.getScalingAdjustment() != null )
scalingPolicy.setScalingAdjustment( request.getScalingAdjustment() );
if ( request.getCooldown() != null )
scalingPolicy.setCooldown( request.getCooldown() );
if ( request.getMinAdjustmentStep() != null )
scalingPolicy.setMinAdjustmentStep( request.getMinAdjustmentStep() );
}
}
} );
reply.getPutScalingPolicyResult().setPolicyARN( scalingPolicy.getPolicyARN() );
} catch ( AutoScalingMetadataNotFoundException e ) {
// Not found, create
final Supplier<ScalingPolicy> allocator = new Supplier<ScalingPolicy>( ) {
@Override
public ScalingPolicy get( ) {
try {
final ScalingPolicies.PersistingBuilder builder = scalingPolicies.create(
accountFullName,
autoScalingGroups.lookup( accountFullName, request.getAutoScalingGroupName() ),
request.getPolicyName(),
Enums.valueOfFunction( AdjustmentType.class ).apply( request.getAdjustmentType() ),
request.getScalingAdjustment() )
.withCooldown( request.getCooldown() )
.withMinAdjustmentStep( request.getMinAdjustmentStep() );

//TODO:STEVE: input validation
// No Auto Scaling name, including policy names, can contain the colon (:) character because colons serve as delimiters in ARNs.
// You will get a ValidationError if you use MinAdjustmentStep on a policy with an AdjustmentType other than PercentChangeInCapacity.
return builder.persist();
} catch ( AutoScalingMetadataNotFoundException e ) {
throw Exceptions.toUndeclared( new InvalidParameterValueException( "Auto scaling group not found: " + request.getAutoScalingGroupName() ) );
} catch ( IllegalArgumentException e ) {
throw Exceptions.toUndeclared( new InvalidParameterValueException( "Invalid adjustment type: " + request.getAdjustmentType() ) );
} catch ( Exception ex ) {
throw new RuntimeException( ex );
}
}
};

try {
final ScalingPolicy scalingPolicy = RestrictedTypes.allocateUnitlessResource( allocator );
reply.getPutScalingPolicyResult().setPolicyARN( scalingPolicy.getPolicyARN() );
} catch ( Exception exception ) {
handleException( exception );
}

} catch ( Exception e ) {
handleException( e );
}

return reply;
}

Expand All @@ -299,8 +435,22 @@ public PutNotificationConfigurationResponseType putNotificationConfiguration(Put
return reply;
}

public DeletePolicyResponseType deletePolicy(DeletePolicyType request) throws EucalyptusCloudException {
DeletePolicyResponseType reply = request.getReply( );
public DeletePolicyResponseType deletePolicy(final DeletePolicyType request) throws EucalyptusCloudException {
final DeletePolicyResponseType reply = request.getReply( );
final Context ctx = Contexts.lookup( );
try {
final ScalingPolicy scalingPolicy = scalingPolicies.lookup(
ctx.getUserFullName( ).asAccountFullName( ),
request.getAutoScalingGroupName(),
request.getPolicyName( ) );
if ( RestrictedTypes.filterPrivileged().apply( scalingPolicy ) ) {
scalingPolicies.delete( scalingPolicy );
} // else treat this as though the configuration does not exist
} catch ( AutoScalingMetadataNotFoundException e ) {
// so nothing to delete, move along
} catch ( Exception e ) {
handleException( e );
}
return reply;
}

Expand Down Expand Up @@ -490,8 +640,14 @@ public DescribeLaunchConfigurationsResponseType describeLaunchConfigurations(Des
return reply;
}

public DescribeAdjustmentTypesResponseType describeAdjustmentTypes(DescribeAdjustmentTypesType request) throws EucalyptusCloudException {
DescribeAdjustmentTypesResponseType reply = request.getReply( );
public DescribeAdjustmentTypesResponseType describeAdjustmentTypes(final DescribeAdjustmentTypesType request) throws EucalyptusCloudException {
final DescribeAdjustmentTypesResponseType reply = request.getReply( );

reply.getDescribeAdjustmentTypesResult().setAdjustmentTypes(
Collections2.transform(
Collections2.filter( EnumSet.allOf( AdjustmentType.class ), RestrictedTypes.filterPrivilegedWithoutOwner() ),
Strings.toStringFunction() ) );

return reply;
}

Expand Down
Expand Up @@ -49,7 +49,7 @@
@PersistenceContext( name = "eucalyptus_autoscaling" )
@Table( name = "metadata_auto_scaling_groups" )
@Cache( usage = CacheConcurrencyStrategy.TRANSACTIONAL )
public class AutoScalingGroup extends AbstractOwnedPersistent implements AutoScalingGroupMetadata {
public class AutoScalingGroup extends AbstractOwnedPersistent implements AutoScalingGroupMetadata {
private static final long serialVersionUID = 1L;

@Column( name = "metadata_max_size", nullable = false )
Expand Down
Expand Up @@ -58,7 +58,7 @@ public abstract AutoScalingGroup update( OwnerFullName ownerFullName,

public abstract boolean delete( AutoScalingGroup autoScalingGroup ) throws AutoScalingMetadataException;

public abstract AutoScalingGroup save( AutoScalingGroup launchConfiguration ) throws AutoScalingMetadataException;
public abstract AutoScalingGroup save( AutoScalingGroup autoScalingGroup ) throws AutoScalingMetadataException;

public final PersistingBuilder create( final OwnerFullName ownerFullName,
final String autoScalingGroupName,
Expand Down

0 comments on commit 0217eee

Please sign in to comment.