def autoscale_rule_create(cmd, client, autoscale_name, resource_group_name, condition, scale, profile_name=DEFAULT_PROFILE_NAME, cooldown=5, source=None, timegrain="avg 1m"): from azure.mgmt.monitor.models import ScaleRule, ScaleAction, ScaleDirection autoscale_settings = client.get(resource_group_name, autoscale_name) profile = next(x for x in autoscale_settings.profiles if x.name == profile_name) condition.metric_resource_uri = source or autoscale_settings.target_resource_uri condition.statistic = timegrain.statistic condition.time_grain = timegrain.time_grain rule = ScaleRule( metric_trigger=condition, scale_action=ScaleAction( direction=scale.direction, type=scale.type, cooldown='PT{}M'.format(cooldown), value=scale.value) ) profile.rules.append(rule) autoscale_settings = client.create_or_update(resource_group_name, autoscale_name, autoscale_settings) profile = next(x for x in autoscale_settings.profiles if x.name == profile_name) # determine if there are unbalanced rules scale_out_rule_count = len([x for x in profile.rules if x.scale_action.direction == ScaleDirection.increase]) scale_in_rule_count = len([x for x in profile.rules if x.scale_action.direction == ScaleDirection.decrease]) if scale_out_rule_count and not scale_in_rule_count: logger.warning("Profile '%s' has rules to scale out but none to scale in. " "Recommend creating at least 1 scale in rule.", profile_name) elif scale_in_rule_count and not scale_out_rule_count: logger.warning("Profile '%s' has rules to scale in but none to scale out. " "Recommend creating at least 1 scale out rule.", profile_name) return rule
def create_rule_instance(params): rule = params.copy() rule['metric_resource_uri'] = rule.get('metric_resource_uri', self.target) rule['time_grain'] = timedelta(minutes=rule.get('time_grain', 0)) rule['time_window'] = timedelta(minutes=rule.get('time_window', 0)) rule['cooldown'] = timedelta(minutes=rule.get('cooldown', 0)) return ScaleRule(metric_trigger=MetricTrigger(**rule), scale_action=ScaleAction(**rule))
def create_autoscaling_settings(ExistingVmScaleSetName, VmScaleSetID, resourceGroupName): NewVmScaleSetName = VmScaleSetID.split('/')[-1] existing_asg = monitor_client.autoscale_settings.get( resource_group_name=resourceGroupName, autoscale_setting_name=ExistingVmScaleSetName) rules = [ ScaleRule( metric_trigger=MetricTrigger( metric_name=i.metric_trigger.metric_name, #metric_namespace=i.metric_trigger.additional_properties['metricNamespace'], metric_resource_uri=VmScaleSetID, time_grain=i.metric_trigger.time_grain, statistic=i.metric_trigger.statistic, time_window=i.metric_trigger.time_window, time_aggregation=i.metric_trigger.time_aggregation, operator=i.metric_trigger.operator, threshold=i.metric_trigger.threshold #dimensions = i.metric_trigger.additional_properties['dimensions'] ), scale_action=i.scale_action) for i in existing_asg.profiles[0].rules ] profile = AutoscaleProfile(name=existing_asg.profiles[0].name, capacity=existing_asg.profiles[0].capacity, rules=rules, fixed_date=None, recurrence=None) parameters = AutoscaleSettingResource( location=existing_asg.location, tags=existing_asg.tags, profiles=[profile], notifications=existing_asg.notifications, enabled=True, autoscale_setting_resource_name=NewVmScaleSetName, target_resource_uri=VmScaleSetID) new_asg = monitor_client.autoscale_settings.create_or_update( resource_group_name=resourceGroupName, autoscale_setting_name=NewVmScaleSetName, parameters=parameters)
def shutdown_scaleset_rule(queue_uri: str) -> ScaleRule: return ScaleRule( # Scale in if there are 0 or more messages in the queue (aka: every time) metric_trigger=MetricTrigger( metric_name="ApproximateMessageCount", metric_resource_uri=queue_uri, # Check every 10 minutes time_grain=timedelta(minutes=5), # The average amount of messages there are in the pool queue time_aggregation=TimeAggregationType.AVERAGE, statistic=MetricStatisticType.SUM, # Over the past 10 minutes time_window=timedelta(minutes=5), operator=ComparisonOperationType.GREATER_THAN_OR_EQUAL, threshold=0, divide_per_instance=False, ), scale_action=ScaleAction( direction=ScaleDirection.DECREASE, type=ScaleType.CHANGE_COUNT, value=1, cooldown=timedelta(minutes=5), ), )
def create_auto_scale_profile( queue_uri: str, min: int, max: int, default: int, scale_out_amount: int, scale_out_cooldown: int, scale_in_amount: int, scale_in_cooldown: int, ) -> AutoscaleProfile: return AutoscaleProfile( name=str(uuid.uuid4()), capacity=ScaleCapacity(minimum=min, maximum=max, default=max), # Auto scale tuning guidance: # https://docs.microsoft.com/en-us/azure/architecture/best-practices/auto-scaling rules=[ ScaleRule( metric_trigger=MetricTrigger( metric_name="ApproximateMessageCount", metric_resource_uri=queue_uri, # Check every 15 minutes time_grain=timedelta(minutes=15), # The average amount of messages there are in the pool queue time_aggregation=TimeAggregationType.AVERAGE, statistic=MetricStatisticType.COUNT, # Over the past 15 minutes time_window=timedelta(minutes=15), # When there's more than 1 message in the pool queue operator=ComparisonOperationType.GREATER_THAN_OR_EQUAL, threshold=1, divide_per_instance=False, ), scale_action=ScaleAction( direction=ScaleDirection.INCREASE, type=ScaleType.CHANGE_COUNT, value=scale_out_amount, cooldown=timedelta(minutes=scale_out_cooldown), ), ), # Scale in ScaleRule( # Scale in if no work in the past 20 mins metric_trigger=MetricTrigger( metric_name="ApproximateMessageCount", metric_resource_uri=queue_uri, # Check every 10 minutes time_grain=timedelta(minutes=10), # The average amount of messages there are in the pool queue time_aggregation=TimeAggregationType.AVERAGE, statistic=MetricStatisticType.SUM, # Over the past 10 minutes time_window=timedelta(minutes=10), # When there's no messages in the pool queue operator=ComparisonOperationType.EQUALS, threshold=0, divide_per_instance=False, ), scale_action=ScaleAction( direction=ScaleDirection.DECREASE, type=ScaleType.CHANGE_COUNT, value=scale_in_amount, cooldown=timedelta(minutes=scale_in_cooldown), ), ), ], )
def autoscale_rule_create(cmd, client, autoscale_name, resource_group_name, condition, scale, profile_name=DEFAULT_PROFILE_NAME, cooldown=5, source=None, timegrain="avg 1m"): from azure.mgmt.monitor.models import ScaleRule, ScaleAction, ScaleDirection from azure.mgmt.core.tools import parse_resource_id, resource_id autoscale_settings = client.get(resource_group_name, autoscale_name) profile = _identify_profile(autoscale_settings.profiles, profile_name) condition.metric_resource_uri = source or autoscale_settings.target_resource_uri condition.statistic = timegrain.statistic condition.time_grain = timegrain.time_grain def preprocess_for_spring_cloud_service(): try: result = parse_resource_id(autoscale_settings.target_resource_uri) if result['namespace'].lower( ) == 'microsoft.appplatform' and result['type'].lower( ) == 'spring': if condition.metric_namespace is None: condition.metric_namespace = "Microsoft.AppPlatform/Spring" logger.warning( 'Set metricNamespace to Microsoft.AppPlatform/Spring') if source is None: condition.metric_resource_uri = resource_id( subscription=result['subscription'], resource_group=result['resource_group'], namespace=result['namespace'], type=result['type'], name=result['name']) logger.warning( 'Set metricResourceUri to Spring Cloud service') except KeyError: pass preprocess_for_spring_cloud_service() rule = ScaleRule(metric_trigger=condition, scale_action=ScaleAction( direction=scale.direction, type=scale.type, cooldown='PT{}M'.format(cooldown), value=scale.value)) profile.rules.append(rule) autoscale_settings = client.create_or_update(resource_group_name, autoscale_name, autoscale_settings) # determine if there are unbalanced rules scale_out_rule_count = len([ x for x in profile.rules if x.scale_action.direction == ScaleDirection.increase ]) scale_in_rule_count = len([ x for x in profile.rules if x.scale_action.direction == ScaleDirection.decrease ]) if scale_out_rule_count and not scale_in_rule_count: logger.warning( "Profile '%s' has rules to scale out but none to scale in. " "Recommend creating at least 1 scale in rule.", profile_name) elif scale_in_rule_count and not scale_out_rule_count: logger.warning( "Profile '%s' has rules to scale in but none to scale out. " "Recommend creating at least 1 scale out rule.", profile_name) return rule