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
Exemple #2
0
    def __call__(self, parser, namespace, values, option_string=None):
        from azure.mgmt.monitor.models import ScaleAction, ScaleType
        if len(values) == 1:
            # workaround because CMD.exe eats > character... Allows condition to be
            # specified as a quoted expression
            values = values[0].split(' ')
        if len(values) != 2:
            from knack.util import CLIError
            raise CLIError('usage error: --scale {in,out,to} VALUE[%]')
        dir_val = values[0]
        amt_val = values[1]
        scale_type = None
        if dir_val == 'to':
            scale_type = ScaleType.exact_count.value
        elif str(amt_val).endswith('%'):
            scale_type = ScaleType.percent_change_count.value
            amt_val = amt_val[:-1]  # strip off the percent
        else:
            scale_type = ScaleType.change_count.value

        scale = ScaleAction(
            direction=get_autoscale_scale_direction_map()[dir_val],
            type=scale_type,
            cooldown=None,  # this will be filled in later
            value=amt_val)
        namespace.scale = scale
 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))
Exemple #4
0
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),
        ),
    )
Exemple #5
0
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