Ejemplo n.º 1
0
def _create_recurring_profile(autoscale_settings,
                              profile_name,
                              start,
                              end,
                              recurrence,
                              capacity,
                              copy_rules=None,
                              timezone=None):
    from azure.mgmt.monitor.models import (AutoscaleProfile, Recurrence,
                                           RecurrentSchedule)
    from azure.cli.command_modules.monitor._autoscale_util import build_autoscale_profile, validate_autoscale_profile
    import dateutil
    from datetime import time
    import json

    def _build_recurrence(base, time):
        recurrence = Recurrence(frequency=base.frequency,
                                schedule=RecurrentSchedule(
                                    time_zone=base.schedule.time_zone,
                                    days=base.schedule.days,
                                    hours=[time.hour],
                                    minutes=[time.minute]))
        return recurrence

    start_time = dateutil.parser.parse(start).time() if start else time(
        hour=0, minute=0)
    end_time = dateutil.parser.parse(end).time() if end else time(hour=23,
                                                                  minute=59)

    default_profile, autoscale_profile = build_autoscale_profile(
        autoscale_settings)
    validate_autoscale_profile(autoscale_profile, start_time, end_time,
                               recurrence)

    start_profile = AutoscaleProfile(name=profile_name,
                                     capacity=capacity,
                                     rules=[],
                                     recurrence=_build_recurrence(
                                         recurrence, start_time))
    _apply_copy_rules(autoscale_settings, start_profile, copy_rules)

    end_profile = AutoscaleProfile(name=json.dumps({
        'name': default_profile.name,
        'for': profile_name
    }),
                                   capacity=default_profile.capacity,
                                   rules=default_profile.rules,
                                   recurrence=_build_recurrence(
                                       recurrence, end_time))
    autoscale_settings.profiles.append(start_profile)
    autoscale_settings.profiles.append(end_profile)
Ejemplo n.º 2
0
def autoscale_create(client,
                     resource,
                     count,
                     autoscale_name=None,
                     resource_group_name=None,
                     min_count=None,
                     max_count=None,
                     location=None,
                     tags=None,
                     disabled=None,
                     actions=None,
                     email_administrator=None,
                     email_coadministrators=None):

    from azure.mgmt.monitor.models import (AutoscaleSettingResource,
                                           AutoscaleProfile,
                                           AutoscaleNotification,
                                           ScaleCapacity, EmailNotification,
                                           WebhookNotification)
    if not autoscale_name:
        from msrestazure.tools import parse_resource_id
        autoscale_name = parse_resource_id(resource)['name']
    min_count = min_count or count
    max_count = max_count or count
    default_profile = AutoscaleProfile(name=DEFAULT_PROFILE_NAME,
                                       capacity=ScaleCapacity(
                                           default=count,
                                           minimum=min_count,
                                           maximum=max_count),
                                       rules=[])
    notification = AutoscaleNotification(email=EmailNotification(
        custom_emails=[],
        send_to_subscription_administrator=email_administrator,
        send_to_subscription_co_administrators=email_coadministrators),
                                         webhooks=[])
    for action in actions or []:
        if isinstance(action, EmailNotification):
            for email in action.custom_emails:
                notification.email.custom_emails.append(email)
        elif isinstance(action, WebhookNotification):
            notification.webhooks.append(action)
    autoscale = AutoscaleSettingResource(
        location=location,
        profiles=[default_profile],
        tags=tags,
        notifications=[notification],
        enabled=not disabled,
        autoscale_setting_resource_name=autoscale_name,
        target_resource_uri=resource)
    if not (min_count == count and max_count == count):
        logger.warning(
            'Follow up with `az monitor autoscale rule create` to add scaling rules.'
        )
    return client.create_or_update(resource_group_name, autoscale_name,
                                   autoscale)
Ejemplo n.º 3
0
def _create_fixed_profile(autoscale_settings, profile_name, start, end, capacity,
                          copy_rules=None, timezone=None):
    from azure.mgmt.monitor.models import AutoscaleProfile, TimeWindow
    if not (start and end):
        from knack.util import CLIError
        raise CLIError('usage error: fixed schedule: --start DATETIME --end DATETIME')
    profile = AutoscaleProfile(
        name=profile_name,
        capacity=capacity,
        rules=[],
        fixed_date=TimeWindow(start=start, end=end, time_zone=timezone),
    )
    _apply_copy_rules(autoscale_settings, profile, copy_rules)
    autoscale_settings.profiles.append(profile)
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)
Ejemplo n.º 5
0
    def exec_module(self, **kwargs):

        for key in list(self.module_arg_spec.keys()) + ['tags']:
            setattr(self, key, kwargs[key])

        results = None
        changed = False

        self.log('Fetching auto scale settings {0}'.format(self.name))
        results = self.get_auto_scale()
        if results and self.state == 'absent':
            # delete
            changed = True
            if not self.check_mode:
                self.delete_auto_scale()
        elif self.state == 'present':

            if not self.location:
                # Set default location
                resource_group = self.get_resource_group(self.resource_group)
                self.location = resource_group.location

            resource_id = self.target
            if isinstance(self.target, dict):
                resource_id = format_resource_id(
                    val=self.target['name'],
                    subscription_id=self.target.get('subscription_id')
                    or self.subscription_id,
                    namespace=self.target['namespace'],
                    types=self.target['types'],
                    resource_group=self.target.get('resource_group')
                    or self.resource_group)
            self.target = resource_id
            resource_name = self.name

            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))

            profiles = [
                AutoscaleProfile(
                    name=p.get('name'),
                    capacity=ScaleCapacity(minimum=p.get('min_count'),
                                           maximum=p.get('max_count'),
                                           default=p.get('count')),
                    rules=[
                        create_rule_instance(r) for r in p.get('rules') or []
                    ],
                    fixed_date=TimeWindow(
                        time_zone=p.get('fixed_date_timezone'),
                        start=p.get('fixed_date_start'),
                        end=p.get('fixed_date_end'))
                    if p.get('fixed_date_timezone') else None,
                    recurrence=Recurrence(
                        frequency=p.get('recurrence_frequency'),
                        schedule=(RecurrentSchedule(
                            time_zone=p.get('recurrence_timezone'),
                            days=p.get('recurrence_days'),
                            hours=p.get('recurrence_hours'),
                            minutes=p.get('recurrence_mins'))))
                    if p.get('recurrence_frequency')
                    and p['recurrence_frequency'] != 'None' else None)
                for p in self.profiles or []
            ]

            notifications = [
                AutoscaleNotification(email=EmailNotification(**n),
                                      webhooks=[
                                          WebhookNotification(service_uri=w)
                                          for w in n.get('webhooks') or []
                                      ]) for n in self.notifications or []
            ]

            if not results:
                # create new
                changed = True
            else:
                # check changed
                resource_name = results.autoscale_setting_resource_name or self.name
                update_tags, tags = self.update_tags(results.tags)
                if update_tags:
                    changed = True
                    self.tags = tags
                if self.target != results.target_resource_uri:
                    changed = True
                if self.enabled != results.enabled:
                    changed = True
                profile_result_set = set(
                    [str(profile_to_dict(p)) for p in results.profiles or []])
                if profile_result_set != set(
                    [str(profile_to_dict(p)) for p in profiles]):
                    changed = True
                notification_result_set = set([
                    str(notification_to_dict(n))
                    for n in results.notifications or []
                ])
                if notification_result_set != set(
                    [str(notification_to_dict(n)) for n in notifications]):
                    changed = True
            if changed:
                # construct the instance will be send to create_or_update api
                results = AutoscaleSettingResource(
                    location=self.location,
                    tags=self.tags,
                    profiles=profiles,
                    notifications=notifications,
                    enabled=self.enabled,
                    autoscale_setting_resource_name=resource_name,
                    target_resource_uri=self.target)
                if not self.check_mode:
                    results = self.create_or_update_auto_scale(results)
                # results should be the dict of the instance
        self.results = auto_scale_to_dict(results)
        self.results['changed'] = changed
        return self.results
Ejemplo n.º 6
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),
                ),
            ),
        ],
    )
Ejemplo n.º 7
0
def build_autoscale_profile(autoscale_settings):
    """ Builds up a logical model of the autoscale weekly schedule. This then has to later be
        translated into objects that work with the Monitor autoscale API. """
    from datetime import time
    import json
    from azure.mgmt.monitor.models import AutoscaleProfile

    def _validate_default_profile(default_profile, profile):
        if profile.capacity.default != default_profile.capacity.default or \
                profile.capacity.minimum != default_profile.capacity.minimum or \
                profile.capacity.maximum != default_profile.capacity.maximum:
            from knack.util import CLIError
            raise CLIError('unable to resolve default profile.')

    recurring_profiles = [x for x in autoscale_settings.profiles if x.recurrence]
    default_profiles = [x for x in autoscale_settings.profiles if not x.recurrence and not x.fixed_date]

    profile_schedule = {
    }

    # find the default profile and ensure that if there are multiple, they are consistent
    default_profile = default_profiles[0] if default_profiles else None
    for p in default_profiles:
        _validate_default_profile(default_profile, p)

    for profile in recurring_profiles:
        # portal creates extra default profiles with JSON names...
        # trying to stay compatible with that
        try:
            # portal-created "default" or end time
            json_name = json.loads(profile.name)
            sched_name = json_name['for']
            end_time = time(hour=profile.recurrence.schedule.hours[0], minute=profile.recurrence.schedule.minutes[0])

            if not default_profile:
                # choose this as default if it is the first
                default_profile = AutoscaleProfile(
                    name='default',
                    capacity=profile.capacity,
                    rules=profile.rules
                )
            else:
                # otherwise ensure it is consistent with the one chosen earlier
                _validate_default_profile(default_profile, profile)

            for day in profile.recurrence.schedule.days:
                if day not in profile_schedule:
                    profile_schedule[day] = {}
                if sched_name in profile_schedule[day]:
                    profile_schedule[day][sched_name]['end'] = end_time
                else:
                    profile_schedule[day][sched_name] = {'end': end_time}
        except ValueError:
            # start time
            sched_name = profile.name
            start_time = time(hour=profile.recurrence.schedule.hours[0], minute=profile.recurrence.schedule.minutes[0])
            for day in profile.recurrence.schedule.days:
                if day not in profile_schedule:
                    profile_schedule[day] = {}
                if sched_name in profile_schedule[day]:
                    profile_schedule[day][sched_name]['start'] = start_time
                    profile_schedule[day][sched_name]['capacity'] = profile.capacity
                    profile_schedule[day][sched_name]['rules'] = profile.rules
                else:
                    profile_schedule[day][sched_name] = {
                        'start': start_time,
                        'capacity': profile.capacity,
                        'rules': profile.rules
                    }

    return default_profile, profile_schedule