Upgrade SDK reference and update metric commands (#4986)

1. Remove azure-monitor SDK reference
2. Upgrade azure-mgmt-monitor reference to 0.4.0
3. Update diagnostics settings
4. Update and refresh monitor action-group commands
5. Refresh the monitor activity-log list command and tests
6. Refresh the metric alert command and tests
7. Refresh the autoscale command
8. Refresh the diagnostic-settings command
9. Refresh the log-profiles command
10.Move custom commands under operations module
11.BREAKING CHANGE: Update metrics command to support multi-dimension
metrics
12.Improve metric list table output
This commit is contained in:
Troy Dai 2017-11-28 09:56:18 -08:00 коммит произвёл GitHub
Родитель 7b46ee4e6e
Коммит 9b7005681e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
32 изменённых файлов: 1553 добавлений и 1239 удалений

Просмотреть файл

@ -365,7 +365,7 @@ class LongRunningOperation(object): # pylint: disable=too-few-public-methods
def _generate_template_progress(self, correlation_id): # pylint: disable=no-self-use
""" gets the progress for template deployments """
from azure.cli.core.commands.client_factory import get_mgmt_service_client
from azure.monitor import MonitorClient
from azure.mgmt.monitor import MonitorManagementClient
if correlation_id is not None: # pylint: disable=too-many-nested-blocks
formatter = "eventTimestamp ge {}"
@ -376,7 +376,7 @@ class LongRunningOperation(object): # pylint: disable=too-few-public-methods
odata_filters = "{} and {} eq '{}'".format(odata_filters, 'correlationId', correlation_id)
activity_log = get_mgmt_service_client(self.cli_ctx, MonitorClient).activity_logs.list(filter=odata_filters)
activity_log = get_mgmt_service_client(MonitorManagementClient).activity_logs.list(filter=odata_filters)
results = []
max_events = 50 # default max value for events in list_activity_log

Просмотреть файл

@ -3,6 +3,12 @@
Release History
===============
0.0.13
++++++
* Update managed SDK reference to 0.4.0
* Remove data plane SDK reference
* BREAKING CHANGE: Add multi-dimension support to metrics command
0.0.12
++++++
* Add activity-log alert commands

Просмотреть файл

@ -24,7 +24,7 @@ def cf_autoscale(kwargs):
def cf_diagnostics(kwargs):
return cf_monitor(kwargs).service_diagnostic_settings
return cf_monitor(kwargs).diagnostic_settings
def cf_log_profiles(kwargs):
@ -39,24 +39,17 @@ def cf_activity_log_alerts(kwargs):
return cf_monitor(kwargs).activity_log_alerts
# DATA CLIENT FACTORIES
def cf_monitor_data(_):
from azure.monitor import MonitorClient
from azure.cli.core.commands.client_factory import get_mgmt_service_client
return get_mgmt_service_client(MonitorClient)
def cf_metrics(kwargs):
return cf_monitor_data(kwargs).metrics
return cf_monitor(kwargs).metrics
def cf_metric_def(kwargs):
return cf_monitor_data(kwargs).metric_definitions
return cf_monitor(kwargs).metric_definitions
def cf_activity_log(kwargs):
return cf_monitor_data(kwargs).activity_logs
return cf_monitor(kwargs).activity_logs
def cf_event_categories(kwargs):
return cf_monitor_data(kwargs).event_categories
return cf_monitor(kwargs).event_categories

Просмотреть файл

@ -12,7 +12,9 @@ def monitor_exception_handler(ex):
# work around for issue: https://github.com/Azure/azure-sdk-for-python/issues/1556
error_payload = ex.response.json()
if 'Code' in error_payload and 'Message' in error_payload:
raise CLIError('Operation failed. {}. [Code: {}]'.format(error_payload['Message'], error_payload['Code']))
message = '{}.'.format(error_payload['Message']) if error_payload['Message'] else 'Operation failed.'
code = '[Code: "{}"]'.format(error_payload['Code']) if error_payload['Code'] else ''
raise CLIError('{} {}'.format(message, code))
else:
raise CLIError(ex)
else:

Просмотреть файл

@ -12,8 +12,6 @@ helps['monitor'] = """
short-summary: Manage the Azure Monitor Service.
"""
# region Alerts
helps['monitor alert'] = """
type: group
short-summary: Manage metric-based alert rules.
@ -126,10 +124,6 @@ helps['monitor alert list-incidents'] = """
short-summary: List all incidents for an alert rule.
"""
# endregion
# region Metrics
helps['monitor metrics'] = """
type: group
short-summary: View Azure resource metrics.
@ -137,12 +131,70 @@ helps['monitor metrics'] = """
helps['monitor metrics list'] = """
type: command
short-summary: List metric values for a resource.
short-summary: List the metric values for a resource.
parameters:
- name: --aggregation
type: string
short-summary: The list of aggregation types (space separated) to retrieve.
- name: --interval
type: string
short-summary: The interval of the metric query. In ISO 8601 duration format, eg "PT1M"
- name: --start-time
type: string
short-summary: The start time of the query. In ISO format with explicit indication of timezone,
1970-01-01T00:00:00Z, 1970-01-01T00:00:00-0500. Defaults to 1 Hour prior to the current time.
- name: --end-time
type: string
short-summary: The end time of the query. In ISO format with explicit indication of timezone,
1970-01-01T00:00:00Z, 1970-01-01T00:00:00-0500. Defaults to current time.
- name: --filter
type: string
short-summary: A string used to reduce the set of metric data returned. eg. "BlobType eq '*'"
- name: --metadata
short-summary: Returns the metadata values instead of metric data
- name: --dimension
type: string
short-summary: The list of dimensions (space separated) the metrics are queried into.
examples:
- name: List a VM's CPU usage for the past hour
text: >
az monitor metrics list --resource <resource id> --metric "Percentage CPU"
- name: List success E2E latency of a storage account and split the data series based on API name
text: >
az monitor metrics list --resource <resource id> --metric SuccessE2ELatency \\
--dimension ApiName
- name: List success E2E latency of a storage account and split the data series based on both API name and geo type
text: >
az monitor metrics list --resource <resource id> --metric SuccessE2ELatency \\
--dimension ApiName GeoType
- name: List success E2E latency of a storage account and split the data series based on both API name and geo type using "--filter" parameter
text: >
az monitor metrics list --resource <resource id> --metric SuccessE2ELatency \\
--filter "ApiName eq '*' and GeoType eq '*'"
- name: List success E2E latency of a storage account and split the data series based on both API name and geo type. Limits the api name to 'DeleteContainer'
text: >
az monitor metrics list --resource <resource id> --metric SuccessE2ELatency \\
--filter "ApiName eq 'DeleteContainer' and GeoType eq '*'"
Filter string reference: https://docs.microsoft.com/en-us/rest/api/monitor/metrics/list
- name: List transactions of a storage account per day since 2017-01-01
text: >
az monitor metrics list --resource <resource id> --metric Transactions \\
--start-time 2017-01-01T00:00:00Z \\
--interval PT24H
- name: List the metadata values for a storage account under transaction metric's api name dimension since 2017
text: >
az monitor metrics list --resource <resource id> --metric Transactions \\
--filter "ApiName eq '*'" \\
--start-time 2017-01-01T00:00:00Z
"""
helps['monitor metrics list-definitions'] = """
type: command
short-summary: List metric definitions for a resource.
short-summary: Lists the metric definitions for the resource.
parameters:
- name: --metric-names
type: string
short-summary: The list of the metrics definitions to be shown.
"""
# endregion
@ -172,6 +224,10 @@ helps['monitor diagnostic-settings create'] = """
- name: --logs
type: string
short-summary: JSON encoded list of logs settings. Use @{file} to load from a file.
- name: --event-hub-name
type: string
short-summary: The name of the event hub. If none is specified, the default event hub will be
selected.
- name: --metrics
type: string
short-summary: JSON encoded list of metric settings. Use @{file} to load from a file.

Просмотреть файл

@ -10,24 +10,34 @@ from azure.cli.core.commands import register_cli_argument, register_extra_cli_ar
from azure.cli.core.commands.parameters import location_type, tags_type, get_three_state_flag
from azure.cli.core.commands.validators import get_default_location_from_resource_group
from azure.cli.command_modules.monitor.actions import \
(AlertAddAction, AlertRemoveAction, ConditionAction, period_type)
from azure.cli.command_modules.monitor.custom import operator_map, aggregation_map
from azure.cli.command_modules.monitor.validators import \
(validate_diagnostic_settings, get_target_resource_validator)
from azure.mgmt.monitor.models.monitor_management_client_enums import \
(ConditionOperator, TimeAggregationOperator)
from azure.mgmt.monitor.models import (LogProfileResource, RetentionPolicy)
from azure.cli.command_modules.monitor.operations.actions import (AlertAddAction, AlertRemoveAction, ConditionAction,
period_type)
from azure.cli.command_modules.monitor.util import get_operator_map, get_aggregation_map
from azure.cli.command_modules.monitor.validators import validate_diagnostic_settings, get_target_resource_validator
from azure.mgmt.monitor.models.monitor_management_client_enums import ConditionOperator, TimeAggregationOperator
from azure.mgmt.monitor.models import LogProfileResource, RetentionPolicy
from knack.arguments import CLIArgumentType, enum_choice_list
# pylint: disable=line-too-long
def register_resource_parameter_context(context, dest, arg_group=None, required=True):
context.register(dest, options_list='--resource', arg_group=arg_group, required=required,
validator=get_target_resource_validator(dest, required), help="Name or ID of the target resource.")
context.extra('namespace', options_list='--resource-namespace', arg_group=arg_group,
help="Target resource provider namespace.")
context.extra('parent', options_list='--resource-parent', arg_group=arg_group,
help="Target resource parent path, if applicable.")
context.extra('resource_type', options_list='--resource-type', arg_group=arg_group,
help="Target resource type. Can also accept namespace/type format "
"(Ex: 'Microsoft.Compute/virtualMachines)')")
context.extra('resource_group_name', options_list=('--resource-group', '-g'), arg_group='Target Resource')
def register_resource_parameter(command, dest, arg_group=None, required=True):
""" Helper method to add the extra parameters needed to support specifying name or ID
for target resources. """
register_cli_argument(command, dest, options_list=['--{}'.format(dest)], arg_group=arg_group, required=required, validator=get_target_resource_validator(dest, required), help="Name or ID of the target resource.")
""" Helper method to add the extra parameters needed to support specifying name or ID for target resources. """
register_cli_argument(command, dest, options_list=['--{}'.format(dest)], arg_group=arg_group, required=required, validator=get_target_resource_validator(dest, required, preserve_resource_group_parameter=True), help="Name or ID of the target resource.")
register_extra_cli_argument(command, 'namespace', options_list=['--{}-namespace'.format(dest)], arg_group=arg_group, help="Target resource provider namespace.")
register_extra_cli_argument(command, 'parent', options_list=['--{}-parent'.format(dest)], arg_group=arg_group, help="Target resource parent path, if applicable.")
register_extra_cli_argument(command, 'resource_type', options_list=['--{}-type'.format(dest)], arg_group=arg_group, help="Target resource type. Can also accept namespace/type format (Ex: 'Microsoft.Compute/virtualMachines)')")
@ -62,9 +72,9 @@ register_cli_argument('monitor alert update', 'add_actions', options_list=['--ad
register_cli_argument('monitor alert update', 'remove_actions', options_list=['--remove-action', '-r'], nargs='+', action=AlertRemoveAction, arg_group='Action')
register_cli_argument('monitor alert update', 'condition', action=ConditionAction, nargs='+', arg_group='Condition')
register_cli_argument('monitor alert update', 'metric', arg_group='Condition')
register_cli_argument('monitor alert update', 'operator', arg_group='Condition', **enum_choice_list(operator_map.keys()))
register_cli_argument('monitor alert update', 'operator', arg_group='Condition', **enum_choice_list(get_operator_map().keys()))
register_cli_argument('monitor alert update', 'threshold', arg_group='Condition')
register_cli_argument('monitor alert update', 'aggregation', arg_group='Condition', **enum_choice_list(aggregation_map.keys()))
register_cli_argument('monitor alert update', 'aggregation', arg_group='Condition', **enum_choice_list(get_aggregation_map().keys()))
register_cli_argument('monitor alert update', 'period', type=period_type, arg_group='Condition')
register_resource_parameter('monitor alert update', 'target', 'Target Resource', required=False)
@ -76,13 +86,26 @@ register_cli_argument('monitor alert list-incidents', 'rule_name', options_list=
# endregion
# region Metrics
with ParametersContext(command='monitor metrics list-definitions') as c:
register_resource_parameter_context(c, dest='resource_uri', arg_group='Target Resource')
for item in ['list', 'list-definitions']:
register_resource_parameter('monitor metrics {}'.format(item), 'resource', 'Target Resource')
register_cli_argument('monitor metrics {}'.format(item), 'resource_group_name', arg_group='Target Resource')
with ParametersContext(command='monitor metrics list') as c:
from .validators import (process_metric_timespan, process_metric_aggregation, process_metric_result_type,
process_metric_dimension)
from azure.mgmt.monitor.models.monitor_management_client_enums import AggregationType
register_resource_parameter_context(c, dest='resource_uri', arg_group='Target Resource')
c.extra('start_time', options_list='--start-time', validator=process_metric_timespan, arg_group='Time')
c.extra('end_time', options_list='--end-time', arg_group='Time')
c.extra('metadata', options_list='--metadata', action='store_true', validator=process_metric_result_type)
c.extra('dimension', options_list='--dimension', nargs='*', validator=process_metric_dimension)
c.argument('interval', arg_group='Time')
c.argument('aggregation', nargs='*', validator=process_metric_aggregation,
**enum_choice_list(t for t in AggregationType if t.name != 'none'))
c.ignore('timespan')
c.ignore('result_type')
c.ignore('top')
c.ignore('orderby')
# endregion
with ParametersContext(command='monitor autoscale-settings') as c:
c.register_alias('name', ('--azure-resource-name',))
c.register_alias('autoscale_setting_name', ('--name', '-n'))
@ -108,8 +131,7 @@ with ParametersContext(command='monitor diagnostic-settings') as c:
with ParametersContext(command='monitor diagnostic-settings create') as c:
c.register_alias('resource_group', ('--resource-group', '-g'))
c.register_alias('target_resource_id', ('--resource-id',),
validator=validate_diagnostic_settings)
c.register_alias('target_resource_id', ('--resource-id',), validator=validate_diagnostic_settings)
c.register('logs', ('--logs',), type=get_json_object)
c.register('metrics', ('--metrics',), type=get_json_object)
c.argument('tags', nargs='*')
@ -135,12 +157,6 @@ with ParametersContext(command='monitor log-profiles create') as c:
help="Space separated list of regions for which Activity Log events "
"should be stored.")
with ParametersContext(command='monitor metric-definitions list') as c:
c.argument('metric_names', nargs='+')
with ParametersContext(command='monitor metrics list') as c:
c.argument('metric_names', nargs='+', required=True)
with ParametersContext(command='monitor activity-log list') as c:
c.register_alias('resource_group', ('--resource-group', '-g'))
c.argument('select', None, nargs='+')
@ -159,7 +175,7 @@ register_cli_argument('monitor action-group', 'action_group_name', options_list=
with ParametersContext(command='monitor action-group create') as c:
from .validators import process_action_group_detail_for_creation
from .actions import ActionGroupReceiverParameterAction
from .operations.actions import ActionGroupReceiverParameterAction
c.extra('receivers', options_list=('--action', '-a'), nargs='+', arg_group='Actions',
action=ActionGroupReceiverParameterAction, validator=process_action_group_detail_for_creation)
@ -181,7 +197,7 @@ register_cli_argument('monitor activity-log alert', 'activity_log_alert_name', o
id_part='name')
with ParametersContext(command='monitor activity-log alert create') as c:
from .activity_log_alerts import webhook_prop_type, process_condition_parameter
from .operations.activity_log_alerts import webhook_prop_type, process_condition_parameter
c.register('disable', options_list='--disable', action='store_true')
c.register('scopes', options_list=('--scope', '-s'), nargs='+')
c.register('condition', options_list=('--condition', '-c'), nargs='+', validator=process_condition_parameter)
@ -194,12 +210,12 @@ with ParametersContext(command='monitor activity-log alert update-condition') as
c.register('remove_conditions', options_list=('--remove-condition', '-r'), nargs='+')
with ParametersContext(command='monitor activity-log alert update') as c:
from .activity_log_alerts import process_condition_parameter
from .operations.activity_log_alerts import process_condition_parameter
c.register('condition', options_list=('--condition', '-c'), nargs='+', validator=process_condition_parameter)
c.register('enabled', options_list='--enabled', **three_state_flag())
with ParametersContext(command='monitor activity-log alert action-group add') as c:
from .activity_log_alerts import webhook_prop_type
from .operations.activity_log_alerts import webhook_prop_type
c.register('reset', options_list='--reset', action='store_true')
c.register('action_group_ids', options_list=('--action-group', '-a'), nargs='+')
c.register('webhook_properties', options_list=('--webhook-properties', '-w'), arg_type=webhook_prop_type)

Просмотреть файл

@ -3,134 +3,115 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
# pylint: disable=line-too-long
from azure.cli.core.commands import cli_command
from azure.cli.core.commands.arm import _cli_generic_update_command
from azure.cli.core.profiles import supported_api_version, PROFILE_TYPE
from ._client_factory import (cf_alert_rules, cf_metrics, cf_metric_def, cf_alert_rule_incidents, cf_log_profiles,
cf_autoscale, cf_diagnostics, cf_activity_log, cf_action_groups, cf_activity_log_alerts,
cf_event_categories)
from ._exception_handler import monitor_exception_handler, missing_resource_handler
from .transformers import (action_group_list_table)
if not supported_api_version(PROFILE_TYPE, max_api='2017-03-09-profile'):
def monitor_command(*args, **kwargs):
cli_command(*args, exception_handler=monitor_exception_handler, **kwargs)
from azure.cli.core.sdk.util import ServiceGroup, create_service_adapter
from ._client_factory import (cf_alert_rules, cf_metrics, cf_metric_def, cf_alert_rule_incidents, cf_log_profiles,
cf_autoscale, cf_diagnostics, cf_activity_log, cf_action_groups,
cf_activity_log_alerts, cf_event_categories)
from ._exception_handler import monitor_exception_handler, missing_resource_handler
# MANAGEMENT COMMANDS
from .transformers import (action_group_list_table)
custom_path = 'azure.cli.command_modules.monitor.custom#'
def service_adapter(module_name, class_name):
return create_service_adapter('azure.mgmt.monitor.operations.{}'.format(module_name), class_name)
# region Alerts
def custom_path(module_name):
return '.'.join(__name__.split('.')[:-1]) + '.operations.{}#'.format(module_name) + '{}'
ar_path = 'azure.mgmt.monitor.operations.alert_rules_operations#AlertRulesOperations.'
monitor_command(__name__, 'monitor alert create', custom_path + 'create_metric_rule', cf_alert_rules)
monitor_command(__name__, 'monitor alert delete', ar_path + 'delete', cf_alert_rules)
monitor_command(__name__, 'monitor alert show', ar_path + 'get', cf_alert_rules)
monitor_command(__name__, 'monitor alert list', ar_path + 'list_by_resource_group', cf_alert_rules)
_cli_generic_update_command(__name__, 'monitor alert update',
ar_path + 'get', ar_path + 'create_or_update', cf_alert_rules,
custom_function_op=custom_path + 'update_metric_rule',
exception_handler=monitor_exception_handler)
ari_path = 'azure.mgmt.monitor.operations.alert_rule_incidents_operations#AlertRuleIncidentsOperations.'
monitor_command(__name__, 'monitor alert show-incident', ari_path + 'get', cf_alert_rule_incidents)
monitor_command(__name__, 'monitor alert list-incidents', ari_path + 'list_by_alert_rule', cf_alert_rule_incidents)
# endregion
# region Metrics
monitor_command(__name__, 'monitor metrics list', custom_path + 'list_metrics', cf_metrics)
monitor_command(__name__, 'monitor metrics list-definitions', custom_path + 'list_metric_definitions', cf_metric_def)
# endregion
# region Log Profiles
lp_path = 'azure.mgmt.monitor.operations.log_profiles_operations#LogProfilesOperations.'
monitor_command(__name__, 'monitor log-profiles create', lp_path + 'create_or_update', cf_log_profiles)
monitor_command(__name__, 'monitor log-profiles delete', lp_path + 'delete', cf_log_profiles)
monitor_command(__name__, 'monitor log-profiles show', lp_path + 'get', cf_log_profiles)
monitor_command(__name__, 'monitor log-profiles list', lp_path + 'list', cf_log_profiles)
_cli_generic_update_command(__name__, 'monitor log-profiles update',
lp_path + 'get', lp_path + 'create_or_update', cf_log_profiles,
exception_handler=monitor_exception_handler)
# endregion
# region Diagnostic Settings
diag_path = 'azure.mgmt.monitor.operations.service_diagnostic_settings_operations#ServiceDiagnosticSettingsOperations.'
monitor_command(__name__, 'monitor diagnostic-settings create', custom_path + 'create_diagnostics_settings', cf_diagnostics)
monitor_command(__name__, 'monitor diagnostic-settings show', diag_path + 'get', cf_diagnostics)
_cli_generic_update_command(__name__, 'monitor diagnostic-settings update',
diag_path + 'get', diag_path + 'create_or_update', cf_diagnostics,
exception_handler=monitor_exception_handler)
# endregion
# region Autoscale
autoscale_path = 'azure.mgmt.monitor.operations.autoscale_settings_operations#AutoscaleSettingsOperations.'
monitor_command(__name__, 'monitor autoscale-settings create', autoscale_path + 'create_or_update', cf_autoscale)
monitor_command(__name__, 'monitor autoscale-settings delete', autoscale_path + 'delete', cf_autoscale)
monitor_command(__name__, 'monitor autoscale-settings show', autoscale_path + 'get', cf_autoscale)
monitor_command(__name__, 'monitor autoscale-settings list', autoscale_path + 'list_by_resource_group', cf_autoscale)
monitor_command(__name__, 'monitor autoscale-settings get-parameters-template', custom_path + 'scaffold_autoscale_settings_parameters', cf_autoscale)
_cli_generic_update_command(__name__, 'monitor autoscale-settings update',
autoscale_path + 'get', autoscale_path + 'create_or_update', cf_autoscale,
exception_handler=monitor_exception_handler)
# endregion
# region Activity Log
monitor_command(__name__, 'monitor activity-log list', custom_path + 'list_activity_log', cf_activity_log)
# endregion
action_group_operations = create_service_adapter(
'azure.mgmt.monitor.operations.action_groups_operations', 'ActionGroupsOperations')
ag_custom_path = '.'.join(__name__.split('.')[:-1] + ['action_groups']) + '#{}'
with ServiceGroup(__name__, cf_action_groups, action_group_operations, ag_custom_path) as s:
with ServiceGroup(__name__, cf_action_groups, service_adapter('action_groups_operations', 'ActionGroupsOperations'),
custom_path('action_groups')) as s:
with s.group('monitor action-group') as c:
c.command('show', 'get', table_transformer=action_group_list_table)
c.command('create', 'create_or_update', table_transformer=action_group_list_table)
c.command('delete', 'delete')
c.command('enable-receiver', 'enable_receiver', table_transformer=action_group_list_table)
c.command('enable-receiver', 'enable_receiver', table_transformer=action_group_list_table,
exception_handler=monitor_exception_handler)
c.custom_command('list', 'list_action_groups', table_transformer=action_group_list_table)
c.generic_update_command('update', 'get', 'create_or_update', 'update_action_groups',
setter_arg_name='action_group',
table_transformer=action_group_list_table,
setter_arg_name='action_group', table_transformer=action_group_list_table,
exception_handler=monitor_exception_handler)
activity_log_alerts_operations = create_service_adapter(
'azure.mgmt.monitor.operations.activity_log_alerts_operations', 'ActivityLogAlertsOperations')
ala_custom_path = '.'.join(__name__.split('.')[:-1] + ['activity_log_alerts']) + '#{}'
with ServiceGroup(__name__, cf_activity_log, custom_path=custom_path('activity_log')) as s:
with s.group('monitor activity-log') as c:
c.custom_command('list', 'list_activity_log')
with ServiceGroup(__name__, cf_activity_log_alerts, activity_log_alerts_operations, ala_custom_path) as s:
with ServiceGroup(__name__, cf_activity_log_alerts,
service_adapter('activity_log_alerts_operations', 'ActivityLogAlertsOperations'),
custom_path('activity_log_alerts')) as s:
with s.group('monitor activity-log alert') as c:
c.custom_command('list', 'list_activity_logs_alert')
c.custom_command('create', 'create', exception_handler=monitor_exception_handler)
c.command('show', 'get', exception_handler=missing_resource_handler)
c.command('delete', 'delete', exception_handler=missing_resource_handler)
c.generic_update_command('update', 'get', 'create_or_update', 'update',
setter_arg_name='activity_log_alert',
exception_handler=monitor_exception_handler)
setter_arg_name='activity_log_alert', exception_handler=monitor_exception_handler)
c.custom_command('action-group add', 'add_action_group', exception_handler=monitor_exception_handler)
c.custom_command('action-group remove', 'remove_action_group', exception_handler=monitor_exception_handler)
c.custom_command('scope add', 'add_scope', exception_handler=monitor_exception_handler)
c.custom_command('scope remove', 'remove_scope', exception_handler=monitor_exception_handler)
with ServiceGroup(__name__, cf_event_categories,
create_service_adapter('azure.monitor.operations.event_categories_operations',
'EventCategoriesOperations'),
ala_custom_path) as s:
service_adapter('event_categories_operations', 'EventCategoriesOperations'),
custom_path('activity_log_alerts')) as s:
with s.group('monitor activity-log') as c:
c.command('list-categories', 'list')
with ServiceGroup(__name__, cf_alert_rules, service_adapter('alert_rules_operations', 'AlertRulesOperations'),
custom_path('metric_alert')) as s:
with s.group('monitor alert') as c:
c.custom_command('create', 'create_metric_rule')
c.command('delete', 'delete')
c.command('show', 'get')
c.command('list', 'list_by_resource_group')
c.generic_update_command('update', 'get', 'create_or_update', 'update_metric_rule',
exception_handler=monitor_exception_handler)
with ServiceGroup(__name__, cf_alert_rule_incidents,
service_adapter('alert_rule_incidents_operations', 'AlertRuleIncidentsOperations'),
custom_path('metric_alert')) as s:
with s.group('monitor alert') as c:
c.command('show-incident', 'get')
c.command('list-incidents', 'list_by_alert_rule')
with ServiceGroup(__name__, cf_autoscale,
service_adapter('autoscale_settings_operations', 'AutoscaleSettingsOperations'),
custom_path('autoscale_settings')) as s:
with s.group('monitor autoscale-settings') as c:
c.command('create', 'create_or_update')
c.command('delete', 'delete')
c.command('show', 'get')
c.command('list', 'list_by_resource_group')
c.custom_command('get-parameters-template', 'scaffold_autoscale_settings_parameters')
c.generic_update_command('update', 'get', 'create_or_update', exception_handler=monitor_exception_handler)
with ServiceGroup(__name__, cf_diagnostics,
service_adapter('diagnostic_settings_operations', 'DiagnosticSettingsOperations'),
custom_path('diagnostics_settings')) as s:
with s.group('monitor diagnostic-settings') as c:
c.custom_command('create', 'create_diagnostics_settings')
c.command('show', 'get')
c.generic_update_command('update', 'get', 'create_or_update', exception_handler=monitor_exception_handler)
with ServiceGroup(__name__, cf_log_profiles,
service_adapter('log_profiles_operations', 'LogProfilesOperations')) as s:
with s.group('monitor log-profiles') as c:
c.command('create', 'create_or_update')
c.command('delete', 'delete')
c.command('show', 'get')
c.command('list', 'list')
c.generic_update_command('update', 'get', 'create_or_update', exception_handler=monitor_exception_handler)
with ServiceGroup(__name__, cf_metrics, service_adapter('metrics_operations', 'MetricsOperations')) as s:
from .transformers import metrics_table
with s.group('monitor metrics') as c:
c.command('list', 'list', table_transformer=metrics_table)
with ServiceGroup(__name__, cf_metric_def,
service_adapter('metric_definitions_operations', 'MetricDefinitionsOperations')) as s:
from .transformers import metrics_definitions_table
with s.group('monitor metrics') as c:
c.command('list-definitions', 'list', table_transformer=metrics_definitions_table)

Просмотреть файл

@ -1,381 +0,0 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
from __future__ import print_function
import datetime
import os
from azure.cli.core.util import get_file_json, CLIError
from azure.mgmt.monitor.models import ConditionOperator, TimeAggregationOperator
# 1 hour in milliseconds
DEFAULT_QUERY_TIME_RANGE = 3600000
# ISO format with explicit indication of timezone
DATE_TIME_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
# region Alerts
operator_map = {
'>': ConditionOperator.greater_than.value,
'>=': ConditionOperator.greater_than_or_equal.value,
'<': ConditionOperator.less_than,
'<=': ConditionOperator.less_than_or_equal
}
aggregation_map = {
'avg': TimeAggregationOperator.average.value,
'min': TimeAggregationOperator.minimum.value,
'max': TimeAggregationOperator.maximum.value,
'total': TimeAggregationOperator.total.value,
'last': TimeAggregationOperator.last.value
}
def _parse_actions(actions):
""" Actions come in as a combined list. This method separates the webhook actions into a
separate collection and combines any number of email actions into a single email collection
and a single value for `email_service_owners`. If any email action contains a True value
for `send_to_service_owners` then it is assumed the entire value should be True. """
from azure.mgmt.monitor.models import RuleEmailAction, RuleWebhookAction
actions = actions or []
email_service_owners = None
webhooks = [x for x in actions if isinstance(x, RuleWebhookAction)]
custom_emails = set()
for action in actions:
if isinstance(action, RuleEmailAction):
if action.send_to_service_owners:
email_service_owners = True
custom_emails = custom_emails | set(action.custom_emails)
return list(custom_emails), webhooks, email_service_owners
def _parse_action_removals(actions):
""" Separates the combined list of keys to remove into webhooks and emails. """
flattened = list(set([x for sublist in actions for x in sublist]))
emails = []
webhooks = []
for item in flattened:
if item.startswith('http://') or item.startswith('https://'):
webhooks.append(item)
else:
emails.append(item)
return emails, webhooks
def create_metric_rule(client, resource_group_name, rule_name, target, condition,
description=None, disabled=False, location=None, tags=None,
email_service_owners=False, actions=None):
from azure.mgmt.monitor.models import AlertRuleResource, RuleEmailAction
condition.data_source.resource_uri = target
custom_emails, webhooks, _ = _parse_actions(actions)
actions = [RuleEmailAction(email_service_owners, custom_emails)] + (webhooks or [])
rule = AlertRuleResource(location, rule_name, not disabled,
condition, tags, description, actions)
return client.create_or_update(resource_group_name, rule_name, rule)
def update_metric_rule(instance, target=None, condition=None, description=None, enabled=None,
metric=None, operator=None, threshold=None, aggregation=None, period=None,
tags=None, email_service_owners=None, add_actions=None, remove_actions=None):
# Update general properties
if description is not None:
instance.description = description
if enabled is not None:
instance.is_enabled = enabled
if tags is not None:
instance.tags = tags
# Update conditions
if condition is not None:
target = target or instance.condition.data_source.resource_uri
instance.condition = condition
if metric is not None:
instance.condition.data_source.metric_name = metric
if operator is not None:
instance.condition.operator = operator_map[operator]
if threshold is not None:
instance.condition.threshold = threshold
if aggregation is not None:
instance.condition.time_aggregation = aggregation_map[aggregation]
if period is not None:
instance.condition.window_size = period
if target is not None:
instance.condition.data_source.resource_uri = target
# Update actions
emails, webhooks, curr_email_service_owners = _parse_actions(instance.actions)
# process removals
if remove_actions is not None:
removed_emails, removed_webhooks = _parse_action_removals(remove_actions)
emails = [x for x in emails if x not in removed_emails]
webhooks = [x for x in webhooks if x.service_uri not in removed_webhooks]
# process additions
if add_actions is not None:
added_emails, added_webhooks, _ = _parse_actions(add_actions)
emails = list(set(emails) | set(added_emails))
webhooks = webhooks + added_webhooks
# Replace the existing actions array. This potentially restructures rules that were created
# via other methods (Portal, ARM template). However, the functionality of these rules should
# be the same.
from azure.mgmt.monitor.models import RuleEmailAction
if email_service_owners is None:
email_service_owners = curr_email_service_owners
actions = [RuleEmailAction(email_service_owners, emails)] + webhooks
instance.actions = actions
return instance
# endregion
# pylint: disable=unused-argument
def list_metric_definitions(client, resource, resource_group_name=None, metric_names=None):
'''Commands to manage metric definitions.
:param str resource_id: The identifier of the resource
:param str metric_names: The list of metric names
'''
odata_filter = _metric_names_filter_builder(metric_names)
metric_definitions = client.list(resource, filter=odata_filter)
return list(metric_definitions)
def _metric_names_filter_builder(metric_names=None):
'''Build up OData filter string from metric_names
'''
filters = []
if metric_names:
for metric_name in metric_names:
filters.append("name.value eq '{}'".format(metric_name))
return ' or '.join(filters)
# pylint: disable=unused-argument
def list_metrics(client, resource, time_grain, resource_group_name=None,
start_time=None, end_time=None, metric_names=None):
'''Lists the metric values for a resource.
:param str resource_id: The identifier of the resource
:param str time_grain: The time grain. Granularity of the metric data returned in ISO 8601
duration format, eg "PT1M"
:param str start_time: The start time of the query. In ISO format with explicit indication of
timezone: 1970-01-01T00:00:00Z, 1970-01-01T00:00:00-0500. Defaults to
1 Hour prior to the current time.
:param str end_time: The end time of the query. In ISO format with explicit indication of
timezone: 1970-01-01T00:00:00Z, 1970-01-01T00:00:00-0500. Defaults to
current time.
:param str metric_names: The space separated list of metric names
'''
odata_filter = _metrics_odata_filter_builder(time_grain, start_time, end_time, metric_names)
metrics = client.list(resource, filter=odata_filter)
return list(metrics)
def _metrics_odata_filter_builder(time_grain, start_time=None, end_time=None,
metric_names=None):
'''Build up OData filter string
'''
filters = []
metrics_filter = _metric_names_filter_builder(metric_names)
if metrics_filter:
filters.append('({})'.format(metrics_filter))
if time_grain:
filters.append("timeGrain eq duration'{}'".format(time_grain))
filters.append(_validate_time_range_and_add_defaults(start_time, end_time))
return ' and '.join(filters)
def _validate_time_range_and_add_defaults(start_time, end_time,
formatter='startTime eq {} and endTime eq {}'):
end_time = _validate_end_time(end_time)
start_time = _validate_start_time(start_time, end_time)
time_range = formatter.format(start_time.strftime('%Y-%m-%dT%H:%M:%SZ'),
end_time.strftime('%Y-%m-%dT%H:%M:%SZ'))
return time_range
def _validate_end_time(end_time):
result_time = datetime.datetime.utcnow()
if isinstance(end_time, str):
result_time = datetime.datetime.strptime(end_time, DATE_TIME_FORMAT)
return result_time
def _validate_start_time(start_time, end_time):
if not isinstance(end_time, datetime.datetime):
raise ValueError("Input '{}' is not valid datetime. Valid example: 2000-12-31T12:59:59Z"
.format(end_time))
result_time = end_time - datetime.timedelta(seconds=DEFAULT_QUERY_TIME_RANGE)
if isinstance(start_time, str):
result_time = datetime.datetime.strptime(start_time, DATE_TIME_FORMAT)
now = datetime.datetime.utcnow()
if result_time > now:
raise ValueError("start_time '{}' is later than Now {}.".format(start_time, now))
return result_time
def list_activity_log(client, filters=None, correlation_id=None, resource_group=None,
resource_id=None, resource_provider=None, start_time=None, end_time=None,
caller=None, status=None, max_events=50, select=None):
'''Provides the list of activity log.
:param str filters: The OData filter for the list activity logs. If this argument is provided
OData Filter Arguments will be ignored
:param str correlation_id: The correlation id of the query
:param str resource_group: The resource group
:param str resource_id: The identifier of the resource
:param str resource_provider: The resource provider
:param str start_time: The start time of the query. In ISO format with explicit indication of
timezone: 1970-01-01T00:00:00Z, 1970-01-01T00:00:00-0500. Defaults to
1 Hour prior to the current time.
:param str end_time: The end time of the query. In ISO format with explicit indication of
timezone: 1970-01-01T00:00:00Z, 1970-01-01T00:00:00-0500. Defaults to
current time.
:param str caller: The caller to look for when querying
:param str status: The status value to query (ex: Failed)
:param str max_events: The maximum number of records to be returned by the command
:param str select: The list of event names
'''
if filters:
odata_filters = filters
else:
collection = [correlation_id, resource_group, resource_id, resource_provider]
if not _single(collection):
raise CLIError("usage error: [--correlation-id ID | --resource-group NAME | "
"--resource-id ID | --resource-provider PROVIDER]")
odata_filters = _build_activity_log_odata_filter(correlation_id, resource_group,
resource_id, resource_provider,
start_time, end_time,
caller, status)
if max_events:
max_events = int(max_events)
select_filters = _activity_log_select_filter_builder(select)
activity_log = client.list(filter=odata_filters, select=select_filters)
return _limit_results(activity_log, max_events)
def _single(collection):
return len([x for x in collection if x]) == 1
def _build_activity_log_odata_filter(correlation_id=None, resource_group=None, resource_id=None,
resource_provider=None, start_time=None, end_time=None,
caller=None, status=None):
'''Builds odata filter string.
:param str correlation_id: The correlation id of the query
:param str resource_group: The resource group
:param str resource_id: The identifier of the resource
:param str resource_provider: The resource provider
:param str start_time: The start time of the query. In ISO format with explicit indication of
timezone: 1970-01-01T00:00:00Z, 1970-01-01T00:00:00-0500
:param str end_time: The end time of the query. In ISO format with explicit indication of
timezone: 1970-01-01T00:00:00Z, 1970-01-01T00:00:00-0500.
:param str caller: The caller to look for when querying
:param str status: The status value to query (ex: Failed)
'''
formatter = "eventTimestamp ge {} and eventTimestamp le {}"
odata_filters = _validate_time_range_and_add_defaults(start_time, end_time,
formatter=formatter)
if correlation_id:
odata_filters = _build_odata_filter(odata_filters, 'correlation_id',
correlation_id, 'correlationId')
elif resource_group:
odata_filters = _build_odata_filter(odata_filters, 'resource_group',
resource_group, 'resourceGroupName')
elif resource_id:
odata_filters = _build_odata_filter(odata_filters, 'resource_id',
resource_id, 'resourceId')
elif resource_provider:
odata_filters = _build_odata_filter(odata_filters, 'resource_provider',
resource_provider, 'resourceProvider')
if caller:
odata_filters = _build_odata_filter(odata_filters, 'caller',
caller, 'caller')
if status:
odata_filters = _build_odata_filter(odata_filters, 'status',
status, 'status')
return odata_filters
def _activity_log_select_filter_builder(events=None):
'''Build up select filter string from events
'''
if events:
return ' , '.join(events)
return None
def _build_odata_filter(default_filter, field_name, field_value, field_label):
if not field_value:
raise CLIError('Value for {} can not be empty.'.format(field_name))
return _add_condition(default_filter, field_label, field_value)
def _add_condition(default_filter, field_label, field_value):
if not field_value:
return default_filter
return "{} and {} eq '{}'".format(default_filter, field_label, field_value)
def _limit_results(paged, limit):
results = []
for index, item in enumerate(paged):
if index < limit:
results.append(item)
else:
break
return list(results)
def scaffold_autoscale_settings_parameters(client): # pylint: disable=unused-argument
'''Scaffold fully formed autoscale-settings' parameters as json template
'''
# Autoscale settings parameter scaffold file path
curr_dir = os.path.dirname(os.path.realpath(__file__))
autoscale_settings_parameter_file_path = os.path.join(
curr_dir, 'autoscale-parameters-template.json')
return _load_autoscale_settings_parameters(autoscale_settings_parameter_file_path)
def _load_autoscale_settings_parameters(file_path):
if not os.path.exists(file_path):
raise CLIError('File {} not found.'.format(file_path))
return get_file_json(file_path)
# pylint: disable=unused-argument
def create_diagnostics_settings(client, target_resource_id, resource_group=None, logs=None,
metrics=None, namespace=None, rule_name=None, tags=None,
service_bus_rule_id=None, storage_account=None, workspace=None):
from azure.mgmt.monitor.models.service_diagnostic_settings_resource import \
ServiceDiagnosticSettingsResource
# https://github.com/Azure/azure-rest-api-specs/issues/1058
parameters = ServiceDiagnosticSettingsResource(location='',
storage_account_id=storage_account,
service_bus_rule_id=service_bus_rule_id,
metrics=metrics,
logs=logs,
workspace_id=workspace,
tags=tags)
return client.create_or_update(target_resource_id, parameters)

Просмотреть файл

@ -7,7 +7,7 @@ import argparse
import re
from knack.util import CLIError
from azure.cli.command_modules.monitor.custom import operator_map, aggregation_map
from ..util import get_aggregation_map, get_operator_map
def period_type(value):
@ -49,9 +49,9 @@ class ConditionAction(argparse.Action):
if len(values) < 5:
raise CLIError('usage error: --condition METRIC {>,>=,<,<=} THRESHOLD {avg,min,max,total,last} DURATION')
metric_name = ' '.join(values[:-4])
operator = operator_map[values[-4]]
operator = get_operator_map()[values[-4]]
threshold = int(values[-3])
aggregation = aggregation_map[values[-2].lower()]
aggregation = get_aggregation_map()[values[-2].lower()]
window = period_type(values[-1])
metric = RuleMetricDataSource(None, metric_name) # target URI will be filled in later
condition = ThresholdRuleCondition(operator, threshold, metric, window, aggregation)

Просмотреть файл

@ -0,0 +1,115 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
from azure.cli.core.util import CLIError
from ..util import validate_time_range_and_add_defaults
def list_activity_log(client, filters=None, correlation_id=None, resource_group=None, resource_id=None,
resource_provider=None, start_time=None, end_time=None, caller=None, status=None, max_events=50,
select=None):
"""Provides the list of activity log.
:param str filters: The OData filter for the list activity logs. If this argument is provided
OData Filter Arguments will be ignored
:param str correlation_id: The correlation id of the query
:param str resource_group: The resource group
:param str resource_id: The identifier of the resource
:param str resource_provider: The resource provider
:param str start_time: The start time of the query. In ISO format with explicit indication of
timezone: 1970-01-01T00:00:00Z, 1970-01-01T00:00:00-0500. Defaults to
1 Hour prior to the current time.
:param str end_time: The end time of the query. In ISO format with explicit indication of
timezone: 1970-01-01T00:00:00Z, 1970-01-01T00:00:00-0500. Defaults to
current time.
:param str caller: The caller to look for when querying
:param str status: The status value to query (ex: Failed)
:param str max_events: The maximum number of records to be returned by the command
:param str select: The list of event names
"""
if filters:
odata_filters = filters
else:
collection = [correlation_id, resource_group, resource_id, resource_provider]
if not _single(collection):
raise CLIError("usage error: [--correlation-id ID | --resource-group NAME | "
"--resource-id ID | --resource-provider PROVIDER]")
odata_filters = _build_activity_log_odata_filter(correlation_id, resource_group, resource_id, resource_provider,
start_time, end_time, caller, status)
if max_events:
max_events = int(max_events)
select_filters = _activity_log_select_filter_builder(select)
activity_log = client.list(filter=odata_filters, select=select_filters)
return _limit_results(activity_log, max_events)
def _build_activity_log_odata_filter(correlation_id=None, resource_group=None, resource_id=None, resource_provider=None,
start_time=None, end_time=None, caller=None, status=None):
"""Builds odata filter string.
:param str correlation_id: The correlation id of the query
:param str resource_group: The resource group
:param str resource_id: The identifier of the resource
:param str resource_provider: The resource provider
:param str start_time: The start time of the query. In ISO format with explicit indication of
timezone: 1970-01-01T00:00:00Z, 1970-01-01T00:00:00-0500
:param str end_time: The end time of the query. In ISO format with explicit indication of
timezone: 1970-01-01T00:00:00Z, 1970-01-01T00:00:00-0500.
:param str caller: The caller to look for when querying
:param str status: The status value to query (ex: Failed)
"""
formatter = "eventTimestamp ge {} and eventTimestamp le {}"
odata_filters = validate_time_range_and_add_defaults(start_time, end_time, formatter=formatter)
if correlation_id:
odata_filters = _build_odata_filter(odata_filters, 'correlation_id', correlation_id, 'correlationId')
elif resource_group:
odata_filters = _build_odata_filter(odata_filters, 'resource_group', resource_group, 'resourceGroupName')
elif resource_id:
odata_filters = _build_odata_filter(odata_filters, 'resource_id', resource_id, 'resourceId')
elif resource_provider:
odata_filters = _build_odata_filter(odata_filters, 'resource_provider', resource_provider, 'resourceProvider')
if caller:
odata_filters = _build_odata_filter(odata_filters, 'caller', caller, 'caller')
if status:
odata_filters = _build_odata_filter(odata_filters, 'status', status, 'status')
return odata_filters
def _activity_log_select_filter_builder(events=None):
"""Build up select filter string from events"""
if events:
return ' , '.join(events)
return None
def _build_odata_filter(default_filter, field_name, field_value, field_label):
if not field_value:
raise CLIError('Value for {} can not be empty.'.format(field_name))
return _add_condition(default_filter, field_label, field_value)
def _add_condition(default_filter, field_label, field_value):
if not field_value:
return default_filter
return "{} and {} eq '{}'".format(default_filter, field_label, field_value)
def _single(collection):
return len([x for x in collection if x]) == 1
def _limit_results(paged, limit):
results = []
for index, item in enumerate(paged):
if index < limit:
results.append(item)
else:
break
return list(results)

Просмотреть файл

@ -0,0 +1,21 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
def scaffold_autoscale_settings_parameters(client): # pylint: disable=unused-argument
"""Scaffold fully formed autoscale-settings' parameters as json template """
import os.path
from azure.cli.core.util import CLIError, get_file_json
# Autoscale settings parameter scaffold file path
curr_dir = os.path.dirname(os.path.realpath(__file__))
autoscale_settings_parameter_file_path = os.path.join(
curr_dir, 'autoscale-parameters-template.json')
if not os.path.exists(autoscale_settings_parameter_file_path):
raise CLIError('File {} not found.'.format(autoscale_settings_parameter_file_path))
return get_file_json(autoscale_settings_parameter_file_path)

Просмотреть файл

@ -0,0 +1,18 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
# pylint: disable=unused-argument
def create_diagnostics_settings(client, target_resource_id, resource_group=None, logs=None, metrics=None,
namespace=None, rule_name=None, tags=None, event_hub_name=None, storage_account=None,
workspace=None):
from azure.mgmt.monitor.models.diagnostic_settings_resource import DiagnosticSettingsResource
# https://github.com/Azure/azure-rest-api-specs/issues/1058
parameters = DiagnosticSettingsResource(storage_account_id=storage_account,
event_hub_name=event_hub_name, metrics=metrics, logs=logs,
workspace_id=workspace)
return client.create_or_update(target_resource_id, parameters)

Просмотреть файл

@ -0,0 +1,105 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
from ..util import get_operator_map, get_aggregation_map
def create_metric_rule(client, resource_group_name, rule_name, target, condition, description=None, disabled=False,
location=None, tags=None, email_service_owners=False, actions=None):
from azure.mgmt.monitor.models import AlertRuleResource, RuleEmailAction
condition.data_source.resource_uri = target
custom_emails, webhooks, _ = _parse_actions(actions)
actions = [RuleEmailAction(email_service_owners, custom_emails)] + (webhooks or [])
rule = AlertRuleResource(location, rule_name, not disabled, condition, tags, description, actions)
return client.create_or_update(resource_group_name, rule_name, rule)
def update_metric_rule(instance, target=None, condition=None, description=None, enabled=None, metric=None,
operator=None, threshold=None, aggregation=None, period=None, tags=None,
email_service_owners=None, add_actions=None, remove_actions=None):
# Update general properties
if description is not None:
instance.description = description
if enabled is not None:
instance.is_enabled = enabled
if tags is not None:
instance.tags = tags
# Update conditions
if condition is not None:
target = target or instance.condition.data_source.resource_uri
instance.condition = condition
if metric is not None:
instance.condition.data_source.metric_name = metric
if operator is not None:
instance.condition.operator = get_operator_map()[operator]
if threshold is not None:
instance.condition.threshold = threshold
if aggregation is not None:
instance.condition.time_aggregation = get_aggregation_map()[aggregation]
if period is not None:
instance.condition.window_size = period
if target is not None:
instance.condition.data_source.resource_uri = target
# Update actions
emails, webhooks, curr_email_service_owners = _parse_actions(instance.actions)
# process removals
if remove_actions is not None:
removed_emails, removed_webhooks = _parse_action_removals(remove_actions)
emails = [x for x in emails if x not in removed_emails]
webhooks = [x for x in webhooks if x.service_uri not in removed_webhooks]
# process additions
if add_actions is not None:
added_emails, added_webhooks, _ = _parse_actions(add_actions)
emails = list(set(emails) | set(added_emails))
webhooks = webhooks + added_webhooks
# Replace the existing actions array. This potentially restructures rules that were created
# via other methods (Portal, ARM template). However, the functionality of these rules should
# be the same.
from azure.mgmt.monitor.models import RuleEmailAction
if email_service_owners is None:
email_service_owners = curr_email_service_owners
actions = [RuleEmailAction(email_service_owners, emails)] + webhooks
instance.actions = actions
return instance
def _parse_actions(actions):
""" Actions come in as a combined list. This method separates the webhook actions into a
separate collection and combines any number of email actions into a single email collection
and a single value for `email_service_owners`. If any email action contains a True value
for `send_to_service_owners` then it is assumed the entire value should be True. """
from azure.mgmt.monitor.models import RuleEmailAction, RuleWebhookAction
actions = actions or []
email_service_owners = None
webhooks = [x for x in actions if isinstance(x, RuleWebhookAction)]
custom_emails = set()
for action in actions:
if isinstance(action, RuleEmailAction):
if action.send_to_service_owners:
email_service_owners = True
custom_emails = custom_emails | set(action.custom_emails)
return list(custom_emails), webhooks, email_service_owners
def _parse_action_removals(actions):
""" Separates the combined list of keys to remove into webhooks and emails. """
flattened = list(set([x for sublist in actions for x in sublist]))
emails = []
webhooks = []
for item in flattened:
if item.startswith('http://') or item.startswith('https://'):
webhooks.append(item)
else:
emails.append(item)
return emails, webhooks

Просмотреть файл

@ -8,9 +8,9 @@ interactions:
Connection: [keep-alive]
Content-Length: ['58']
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.2 (Darwin-16.7.0-x86_64-i386-64bit) requests/2.18.4
msrest/0.4.16 msrest_azure/0.4.14 resourcemanagementclient/1.2.0rc3 Azure-SDK-For-Python
AZURECLI/2.0.18+dev]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.19
msrest_azure/0.4.17 resourcemanagementclient/1.2.1 Azure-SDK-For-Python
AZURECLI/2.0.22]
accept-language: [en-US]
method: PUT
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001?api-version=2017-05-10
@ -20,11 +20,11 @@ interactions:
cache-control: [no-cache]
content-length: ['336']
content-type: [application/json; charset=utf-8]
date: ['Mon, 16 Oct 2017 18:10:14 GMT']
date: ['Sun, 26 Nov 2017 05:21:18 GMT']
expires: ['-1']
pragma: [no-cache]
strict-transport-security: [max-age=31536000; includeSubDomains]
x-ms-ratelimit-remaining-subscription-writes: ['1198']
x-ms-ratelimit-remaining-subscription-writes: ['1199']
status: {code: 201, message: Created}
- request:
body: '{"location": "global", "properties": {"groupShortName": "cliactiongro",
@ -37,24 +37,23 @@ interactions:
Connection: [keep-alive]
Content-Length: ['155']
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.2 (Darwin-16.7.0-x86_64-i386-64bit) requests/2.18.4
msrest/0.4.16 msrest_azure/0.4.14 monitormanagementclient/0.3.0 Azure-SDK-For-Python
AZURECLI/2.0.18+dev]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.19
msrest_azure/0.4.17 monitormanagementclient/0.4.0 Azure-SDK-For-Python AZURECLI/2.0.22]
accept-language: [en-US]
method: PUT
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002?api-version=2017-04-01
response:
body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002","type":"Microsoft.Insights/ActionGroups","name":"cliactiongrouptest000002","location":"Global","kind":null,"tags":null,"properties":{"groupShortName":"cliactiongro","enabled":true,"emailReceivers":[],"smsReceivers":[],"webhookReceivers":[],"itsmReceivers":[],"azureAppPushReceivers":[]},"identity":null}'}
body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002","type":"Microsoft.Insights/ActionGroups","name":"cliactiongrouptest000002","location":"Global","kind":null,"tags":null,"properties":{"groupShortName":"cliactiongro","enabled":true,"emailReceivers":[],"smsReceivers":[],"webhookReceivers":[],"itsmReceivers":[],"azureAppPushReceivers":[],"automationRunbookReceivers":[]},"identity":null}'}
headers:
cache-control: [no-cache]
content-length: ['537']
content-length: ['569']
content-type: [application/json; charset=utf-8]
date: ['Mon, 16 Oct 2017 18:10:15 GMT']
date: ['Sun, 26 Nov 2017 05:21:20 GMT']
expires: ['-1']
pragma: [no-cache]
server: [Microsoft-IIS/8.5]
strict-transport-security: [max-age=31536000; includeSubDomains]
x-ms-ratelimit-remaining-subscription-writes: ['1198']
x-ms-ratelimit-remaining-subscription-writes: ['1199']
status: {code: 201, message: Created}
- request:
body: null
@ -64,19 +63,18 @@ interactions:
CommandName: [monitor action-group list]
Connection: [keep-alive]
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.2 (Darwin-16.7.0-x86_64-i386-64bit) requests/2.18.4
msrest/0.4.16 msrest_azure/0.4.14 monitormanagementclient/0.3.0 Azure-SDK-For-Python
AZURECLI/2.0.18+dev]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.19
msrest_azure/0.4.17 monitormanagementclient/0.4.0 Azure-SDK-For-Python AZURECLI/2.0.22]
accept-language: [en-US]
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups?api-version=2017-04-01
response:
body: {string: '{"value":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002","type":"Microsoft.Insights/ActionGroups","name":"cliactiongrouptest000002","location":"Global","kind":null,"tags":null,"properties":{"groupShortName":"cliactiongro","enabled":true,"emailReceivers":[],"smsReceivers":[],"webhookReceivers":[],"itsmReceivers":[],"azureAppPushReceivers":[]},"identity":null}]}'}
body: {string: '{"value":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002","type":"Microsoft.Insights/ActionGroups","name":"cliactiongrouptest000002","location":"Global","kind":null,"tags":null,"properties":{"groupShortName":"cliactiongro","enabled":true,"emailReceivers":[],"smsReceivers":[],"webhookReceivers":[],"itsmReceivers":[],"azureAppPushReceivers":[],"automationRunbookReceivers":[]},"identity":null}]}'}
headers:
cache-control: [no-cache]
content-length: ['549']
content-length: ['581']
content-type: [application/json; charset=utf-8]
date: ['Mon, 16 Oct 2017 18:10:16 GMT']
date: ['Sun, 26 Nov 2017 05:21:20 GMT']
expires: ['-1']
pragma: [no-cache]
server: [Microsoft-IIS/8.5]
@ -92,19 +90,18 @@ interactions:
CommandName: [monitor action-group update]
Connection: [keep-alive]
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.2 (Darwin-16.7.0-x86_64-i386-64bit) requests/2.18.4
msrest/0.4.16 msrest_azure/0.4.14 monitormanagementclient/0.3.0 Azure-SDK-For-Python
AZURECLI/2.0.18+dev]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.19
msrest_azure/0.4.17 monitormanagementclient/0.4.0 Azure-SDK-For-Python AZURECLI/2.0.22]
accept-language: [en-US]
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002?api-version=2017-04-01
response:
body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002","type":"Microsoft.Insights/ActionGroups","name":"cliactiongrouptest000002","location":"Global","kind":null,"tags":null,"properties":{"groupShortName":"cliactiongro","enabled":true,"emailReceivers":[],"smsReceivers":[],"webhookReceivers":[],"itsmReceivers":[],"azureAppPushReceivers":[]},"identity":null}'}
body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002","type":"Microsoft.Insights/ActionGroups","name":"cliactiongrouptest000002","location":"Global","kind":null,"tags":null,"properties":{"groupShortName":"cliactiongro","enabled":true,"emailReceivers":[],"smsReceivers":[],"webhookReceivers":[],"itsmReceivers":[],"azureAppPushReceivers":[],"automationRunbookReceivers":[]},"identity":null}'}
headers:
cache-control: [no-cache]
content-length: ['537']
content-length: ['569']
content-type: [application/json; charset=utf-8]
date: ['Mon, 16 Oct 2017 18:10:17 GMT']
date: ['Sun, 26 Nov 2017 05:21:21 GMT']
expires: ['-1']
pragma: [no-cache]
server: [Microsoft-IIS/8.5]
@ -123,19 +120,18 @@ interactions:
Connection: [keep-alive]
Content-Length: ['179']
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.2 (Darwin-16.7.0-x86_64-i386-64bit) requests/2.18.4
msrest/0.4.16 msrest_azure/0.4.14 monitormanagementclient/0.3.0 Azure-SDK-For-Python
AZURECLI/2.0.18+dev]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.19
msrest_azure/0.4.17 monitormanagementclient/0.4.0 Azure-SDK-For-Python AZURECLI/2.0.22]
accept-language: [en-US]
method: PUT
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002?api-version=2017-04-01
response:
body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002","type":"Microsoft.Insights/ActionGroups","name":"cliactiongrouptest000002","location":"Global","kind":null,"tags":{"owner":"alice"},"properties":{"groupShortName":"new_name","enabled":true,"emailReceivers":[],"smsReceivers":[],"webhookReceivers":[],"itsmReceivers":[],"azureAppPushReceivers":[]},"identity":null}'}
body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002","type":"Microsoft.Insights/ActionGroups","name":"cliactiongrouptest000002","location":"Global","kind":null,"tags":{"owner":"alice"},"properties":{"groupShortName":"new_name","enabled":true,"emailReceivers":[],"smsReceivers":[],"webhookReceivers":[],"itsmReceivers":[],"azureAppPushReceivers":[],"automationRunbookReceivers":[]},"identity":null}'}
headers:
cache-control: [no-cache]
content-length: ['546']
content-length: ['578']
content-type: [application/json; charset=utf-8]
date: ['Mon, 16 Oct 2017 18:10:19 GMT']
date: ['Sun, 26 Nov 2017 05:21:23 GMT']
expires: ['-1']
pragma: [no-cache]
server: [Microsoft-IIS/8.5]
@ -152,19 +148,18 @@ interactions:
CommandName: [monitor action-group update]
Connection: [keep-alive]
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.2 (Darwin-16.7.0-x86_64-i386-64bit) requests/2.18.4
msrest/0.4.16 msrest_azure/0.4.14 monitormanagementclient/0.3.0 Azure-SDK-For-Python
AZURECLI/2.0.18+dev]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.19
msrest_azure/0.4.17 monitormanagementclient/0.4.0 Azure-SDK-For-Python AZURECLI/2.0.22]
accept-language: [en-US]
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002?api-version=2017-04-01
response:
body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002","type":"Microsoft.Insights/ActionGroups","name":"cliactiongrouptest000002","location":"Global","kind":null,"tags":null,"properties":{"groupShortName":"cliactiongro","enabled":true,"emailReceivers":[],"smsReceivers":[],"webhookReceivers":[],"itsmReceivers":[],"azureAppPushReceivers":[]},"identity":null}'}
body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002","type":"Microsoft.Insights/ActionGroups","name":"cliactiongrouptest000002","location":"Global","kind":null,"tags":{"owner":"alice"},"properties":{"groupShortName":"new_name","enabled":true,"emailReceivers":[],"smsReceivers":[],"webhookReceivers":[],"itsmReceivers":[],"azureAppPushReceivers":[],"automationRunbookReceivers":[]},"identity":null}'}
headers:
cache-control: [no-cache]
content-length: ['537']
content-length: ['578']
content-type: [application/json; charset=utf-8]
date: ['Mon, 16 Oct 2017 18:10:19 GMT']
date: ['Sun, 26 Nov 2017 05:21:23 GMT']
expires: ['-1']
pragma: [no-cache]
server: [Microsoft-IIS/8.5]
@ -173,37 +168,37 @@ interactions:
vary: [Accept-Encoding]
status: {code: 200, message: OK}
- request:
body: '{"location": "Global", "properties": {"groupShortName": "cliactiongro",
"enabled": true, "emailReceivers": [{"name": "alice", "emailAddress": "alice@example.com"}],
"smsReceivers": [{"name": "alice_sms", "countryCode": "1", "phoneNumber": "5551234567"}],
"webhookReceivers": [{"name": "alice_web", "serviceUri": "https://www.example.com/alert?name=alice"}]}}'
body: '{"location": "Global", "tags": {"owner": "alice"}, "properties": {"groupShortName":
"new_name", "enabled": true, "emailReceivers": [{"name": "alice", "emailAddress":
"alice@example.com"}], "smsReceivers": [{"name": "alice_sms", "countryCode":
"1", "phoneNumber": "5551234567"}], "webhookReceivers": [{"name": "alice_web",
"serviceUri": "https://www.example.com/alert?name=alice"}]}}'
headers:
Accept: [application/json]
Accept-Encoding: ['gzip, deflate']
CommandName: [monitor action-group update]
Connection: [keep-alive]
Content-Length: ['358']
Content-Length: ['382']
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.2 (Darwin-16.7.0-x86_64-i386-64bit) requests/2.18.4
msrest/0.4.16 msrest_azure/0.4.14 monitormanagementclient/0.3.0 Azure-SDK-For-Python
AZURECLI/2.0.18+dev]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.19
msrest_azure/0.4.17 monitormanagementclient/0.4.0 Azure-SDK-For-Python AZURECLI/2.0.22]
accept-language: [en-US]
method: PUT
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002?api-version=2017-04-01
response:
body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002","type":"Microsoft.Insights/ActionGroups","name":"cliactiongrouptest000002","location":"Global","kind":null,"tags":null,"properties":{"groupShortName":"cliactiongro","enabled":true,"emailReceivers":[{"name":"alice","emailAddress":"alice@example.com","status":"Enabled"}],"smsReceivers":[{"name":"alice_sms","countryCode":"1","phoneNumber":"5551234567","status":"Enabled"}],"webhookReceivers":[{"name":"alice_web","serviceUri":"https://www.example.com/alert?name=alice"}],"itsmReceivers":[],"azureAppPushReceivers":[]},"identity":null}'}
body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002","type":"Microsoft.Insights/ActionGroups","name":"cliactiongrouptest000002","location":"Global","kind":null,"tags":{"owner":"alice"},"properties":{"groupShortName":"new_name","enabled":true,"emailReceivers":[{"name":"alice","emailAddress":"alice@example.com","status":"Enabled"}],"smsReceivers":[{"name":"alice_sms","countryCode":"1","phoneNumber":"5551234567","status":"Enabled"}],"webhookReceivers":[{"name":"alice_web","serviceUri":"https://www.example.com/alert?name=alice"}],"itsmReceivers":[],"azureAppPushReceivers":[],"automationRunbookReceivers":[]},"identity":null}'}
headers:
cache-control: [no-cache]
content-length: ['767']
content-length: ['808']
content-type: [application/json; charset=utf-8]
date: ['Mon, 16 Oct 2017 18:10:22 GMT']
date: ['Sun, 26 Nov 2017 05:21:25 GMT']
expires: ['-1']
pragma: [no-cache]
server: [Microsoft-IIS/8.5]
strict-transport-security: [max-age=31536000; includeSubDomains]
transfer-encoding: [chunked]
vary: [Accept-Encoding]
x-ms-ratelimit-remaining-subscription-writes: ['1198']
x-ms-ratelimit-remaining-subscription-writes: ['1199']
status: {code: 200, message: OK}
- request:
body: null
@ -213,19 +208,18 @@ interactions:
CommandName: [monitor action-group update]
Connection: [keep-alive]
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.2 (Darwin-16.7.0-x86_64-i386-64bit) requests/2.18.4
msrest/0.4.16 msrest_azure/0.4.14 monitormanagementclient/0.3.0 Azure-SDK-For-Python
AZURECLI/2.0.18+dev]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.19
msrest_azure/0.4.17 monitormanagementclient/0.4.0 Azure-SDK-For-Python AZURECLI/2.0.22]
accept-language: [en-US]
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002?api-version=2017-04-01
response:
body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002","type":"Microsoft.Insights/ActionGroups","name":"cliactiongrouptest000002","location":"Global","kind":null,"tags":null,"properties":{"groupShortName":"cliactiongro","enabled":true,"emailReceivers":[{"name":"alice","emailAddress":"alice@example.com","status":"Enabled"}],"smsReceivers":[{"name":"alice_sms","countryCode":"1","phoneNumber":"5551234567","status":"Enabled"}],"webhookReceivers":[{"name":"alice_web","serviceUri":"https://www.example.com/alert?name=alice"}],"itsmReceivers":[],"azureAppPushReceivers":[]},"identity":null}'}
body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002","type":"Microsoft.Insights/ActionGroups","name":"cliactiongrouptest000002","location":"Global","kind":null,"tags":{"owner":"alice"},"properties":{"groupShortName":"new_name","enabled":true,"emailReceivers":[{"name":"alice","emailAddress":"alice@example.com","status":"Enabled"}],"smsReceivers":[{"name":"alice_sms","countryCode":"1","phoneNumber":"5551234567","status":"Enabled"}],"webhookReceivers":[{"name":"alice_web","serviceUri":"https://www.example.com/alert?name=alice"}],"itsmReceivers":[],"azureAppPushReceivers":[],"automationRunbookReceivers":[]},"identity":null}'}
headers:
cache-control: [no-cache]
content-length: ['767']
content-length: ['808']
content-type: [application/json; charset=utf-8]
date: ['Mon, 16 Oct 2017 18:10:23 GMT']
date: ['Sun, 26 Nov 2017 05:21:25 GMT']
expires: ['-1']
pragma: [no-cache]
server: [Microsoft-IIS/8.5]
@ -234,30 +228,29 @@ interactions:
vary: [Accept-Encoding]
status: {code: 200, message: OK}
- request:
body: '{"location": "Global", "properties": {"groupShortName": "cliactiongro",
"enabled": true, "emailReceivers": [{"name": "alice", "emailAddress": "alice@example.com"}],
"smsReceivers": [{"name": "alice_sms", "countryCode": "1", "phoneNumber": "5551234567"}],
"webhookReceivers": []}}'
body: '{"location": "Global", "tags": {"owner": "alice"}, "properties": {"groupShortName":
"new_name", "enabled": true, "emailReceivers": [{"name": "alice", "emailAddress":
"alice@example.com"}], "smsReceivers": [{"name": "alice_sms", "countryCode":
"1", "phoneNumber": "5551234567"}], "webhookReceivers": []}}'
headers:
Accept: [application/json]
Accept-Encoding: ['gzip, deflate']
CommandName: [monitor action-group update]
Connection: [keep-alive]
Content-Length: ['279']
Content-Length: ['303']
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.2 (Darwin-16.7.0-x86_64-i386-64bit) requests/2.18.4
msrest/0.4.16 msrest_azure/0.4.14 monitormanagementclient/0.3.0 Azure-SDK-For-Python
AZURECLI/2.0.18+dev]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.19
msrest_azure/0.4.17 monitormanagementclient/0.4.0 Azure-SDK-For-Python AZURECLI/2.0.22]
accept-language: [en-US]
method: PUT
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002?api-version=2017-04-01
response:
body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002","type":"Microsoft.Insights/ActionGroups","name":"cliactiongrouptest000002","location":"Global","kind":null,"tags":null,"properties":{"groupShortName":"cliactiongro","enabled":true,"emailReceivers":[{"name":"alice","emailAddress":"alice@example.com","status":"Enabled"}],"smsReceivers":[{"name":"alice_sms","countryCode":"1","phoneNumber":"5551234567","status":"Enabled"}],"webhookReceivers":[],"itsmReceivers":[],"azureAppPushReceivers":[]},"identity":null}'}
body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002","type":"Microsoft.Insights/ActionGroups","name":"cliactiongrouptest000002","location":"Global","kind":null,"tags":{"owner":"alice"},"properties":{"groupShortName":"new_name","enabled":true,"emailReceivers":[{"name":"alice","emailAddress":"alice@example.com","status":"Enabled"}],"smsReceivers":[{"name":"alice_sms","countryCode":"1","phoneNumber":"5551234567","status":"Enabled"}],"webhookReceivers":[],"itsmReceivers":[],"azureAppPushReceivers":[],"automationRunbookReceivers":[]},"identity":null}'}
headers:
cache-control: [no-cache]
content-length: ['691']
content-length: ['732']
content-type: [application/json; charset=utf-8]
date: ['Mon, 16 Oct 2017 18:10:23 GMT']
date: ['Sun, 26 Nov 2017 05:21:27 GMT']
expires: ['-1']
pragma: [no-cache]
server: [Microsoft-IIS/8.5]
@ -275,9 +268,8 @@ interactions:
Connection: [keep-alive]
Content-Length: ['28']
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.2 (Darwin-16.7.0-x86_64-i386-64bit) requests/2.18.4
msrest/0.4.16 msrest_azure/0.4.14 monitormanagementclient/0.3.0 Azure-SDK-For-Python
AZURECLI/2.0.18+dev]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.19
msrest_azure/0.4.17 monitormanagementclient/0.4.0 Azure-SDK-For-Python AZURECLI/2.0.22]
accept-language: [en-US]
method: POST
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002/subscribe?api-version=2017-04-01
@ -287,12 +279,12 @@ interactions:
cache-control: [no-cache]
content-length: ['42']
content-type: [application/json; charset=utf-8]
date: ['Mon, 16 Oct 2017 18:10:25 GMT']
date: ['Sun, 26 Nov 2017 05:21:27 GMT']
expires: ['-1']
pragma: [no-cache]
server: [Microsoft-IIS/8.5]
strict-transport-security: [max-age=31536000; includeSubDomains]
x-ms-ratelimit-remaining-subscription-writes: ['1196']
x-ms-ratelimit-remaining-subscription-writes: ['1198']
status: {code: 404, message: Not Found}
- request:
body: '{"receiverName": "alice"}'
@ -303,9 +295,8 @@ interactions:
Connection: [keep-alive]
Content-Length: ['25']
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.2 (Darwin-16.7.0-x86_64-i386-64bit) requests/2.18.4
msrest/0.4.16 msrest_azure/0.4.14 monitormanagementclient/0.3.0 Azure-SDK-For-Python
AZURECLI/2.0.18+dev]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.19
msrest_azure/0.4.17 monitormanagementclient/0.4.0 Azure-SDK-For-Python AZURECLI/2.0.22]
accept-language: [en-US]
method: POST
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002/subscribe?api-version=2017-04-01
@ -315,12 +306,12 @@ interactions:
cache-control: [no-cache]
content-length: ['48']
content-type: [application/json; charset=utf-8]
date: ['Mon, 16 Oct 2017 18:10:25 GMT']
date: ['Sun, 26 Nov 2017 05:21:28 GMT']
expires: ['-1']
pragma: [no-cache]
server: [Microsoft-IIS/8.5]
strict-transport-security: [max-age=31536000; includeSubDomains]
x-ms-ratelimit-remaining-subscription-writes: ['1195']
x-ms-ratelimit-remaining-subscription-writes: ['1199']
status: {code: 409, message: Conflict}
- request:
body: null
@ -331,9 +322,8 @@ interactions:
Connection: [keep-alive]
Content-Length: ['0']
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.2 (Darwin-16.7.0-x86_64-i386-64bit) requests/2.18.4
msrest/0.4.16 msrest_azure/0.4.14 monitormanagementclient/0.3.0 Azure-SDK-For-Python
AZURECLI/2.0.18+dev]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.19
msrest_azure/0.4.17 monitormanagementclient/0.4.0 Azure-SDK-For-Python AZURECLI/2.0.22]
accept-language: [en-US]
method: DELETE
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups/cliactiongrouptest000002?api-version=2017-04-01
@ -342,7 +332,7 @@ interactions:
headers:
cache-control: [no-cache]
content-length: ['0']
date: ['Mon, 16 Oct 2017 18:10:26 GMT']
date: ['Sun, 26 Nov 2017 05:21:30 GMT']
expires: ['-1']
pragma: [no-cache]
server: [Microsoft-IIS/8.5]
@ -357,9 +347,8 @@ interactions:
CommandName: [monitor action-group list]
Connection: [keep-alive]
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.2 (Darwin-16.7.0-x86_64-i386-64bit) requests/2.18.4
msrest/0.4.16 msrest_azure/0.4.14 monitormanagementclient/0.3.0 Azure-SDK-For-Python
AZURECLI/2.0.18+dev]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.19
msrest_azure/0.4.17 monitormanagementclient/0.4.0 Azure-SDK-For-Python AZURECLI/2.0.22]
accept-language: [en-US]
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/microsoft.insights/actionGroups?api-version=2017-04-01
@ -369,7 +358,7 @@ interactions:
cache-control: [no-cache]
content-length: ['12']
content-type: [application/json; charset=utf-8]
date: ['Mon, 16 Oct 2017 18:10:28 GMT']
date: ['Sun, 26 Nov 2017 05:21:31 GMT']
expires: ['-1']
pragma: [no-cache]
server: [Microsoft-IIS/8.5]
@ -386,9 +375,9 @@ interactions:
Connection: [keep-alive]
Content-Length: ['0']
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.2 (Darwin-16.7.0-x86_64-i386-64bit) requests/2.18.4
msrest/0.4.16 msrest_azure/0.4.14 resourcemanagementclient/1.2.0rc3 Azure-SDK-For-Python
AZURECLI/2.0.18+dev]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.19
msrest_azure/0.4.17 resourcemanagementclient/1.2.1 Azure-SDK-For-Python
AZURECLI/2.0.22]
accept-language: [en-US]
method: DELETE
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001?api-version=2017-05-10
@ -397,9 +386,9 @@ interactions:
headers:
cache-control: [no-cache]
content-length: ['0']
date: ['Mon, 16 Oct 2017 18:10:29 GMT']
date: ['Sun, 26 Nov 2017 05:21:32 GMT']
expires: ['-1']
location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/operationresults/eyJqb2JJZCI6IlJFU09VUkNFR1JPVVBERUxFVElPTkpPQi1DTElURVNUOjJFUkdWM1hKSkJJUEVTTzZZUzZaTFpGNjU1VDZMRENBM0ZBUjZXRHxCNjc1NDE1N0VDN0Y2RUM4LVNPVVRIQ0VOVFJBTFVTIiwiam9iTG9jYXRpb24iOiJzb3V0aGNlbnRyYWx1cyJ9?api-version=2017-05-10']
location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/operationresults/eyJqb2JJZCI6IlJFU09VUkNFR1JPVVBERUxFVElPTkpPQi1DTElURVNUOjJFUkc2UVlDUFdNTUhLVFJOVFI3WDQyQkFXTllDRVBSU0FTNU9IT3xGQkUzQjI0NTc0NzYyQTE3LVNPVVRIQ0VOVFJBTFVTIiwiam9iTG9jYXRpb24iOiJzb3V0aGNlbnRyYWx1cyJ9?api-version=2017-05-10']
pragma: [no-cache]
strict-transport-security: [max-age=31536000; includeSubDomains]
x-ms-ratelimit-remaining-subscription-writes: ['1198']

Просмотреть файл

@ -0,0 +1,235 @@
interactions:
- request:
body: '{"location": "southcentralus", "tags": {"use": "az-test"}}'
headers:
Accept: [application/json]
Accept-Encoding: ['gzip, deflate']
CommandName: [group create]
Connection: [keep-alive]
Content-Length: ['58']
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.18
msrest_azure/0.4.16 resourcemanagementclient/1.2.1 Azure-SDK-For-Python
AZURECLI/2.0.21]
accept-language: [en-US]
method: PUT
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001?api-version=2017-05-10
response:
body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001","name":"clitest.rg000001","location":"southcentralus","tags":{"use":"az-test"},"properties":{"provisioningState":"Succeeded"}}'}
headers:
cache-control: [no-cache]
content-length: ['336']
content-type: [application/json; charset=utf-8]
date: ['Mon, 13 Nov 2017 18:22:01 GMT']
expires: ['-1']
pragma: [no-cache]
strict-transport-security: [max-age=31536000; includeSubDomains]
x-ms-ratelimit-remaining-subscription-writes: ['1199']
status: {code: 201, message: Created}
- request:
body: '{"sku": {"name": "Standard_LRS"}, "kind": "Storage", "location": "westus",
"properties": {"supportsHttpsTrafficOnly": false}}'
headers:
Accept: [application/json]
Accept-Encoding: ['gzip, deflate']
CommandName: [storage account create]
Connection: [keep-alive]
Content-Length: ['125']
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.18
msrest_azure/0.4.16 storagemanagementclient/1.4.0 Azure-SDK-For-Python AZURECLI/2.0.21]
accept-language: [en-US]
method: PUT
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002?api-version=2017-06-01
response:
body: {string: ''}
headers:
cache-control: [no-cache]
content-length: ['0']
date: ['Mon, 13 Nov 2017 18:22:12 GMT']
expires: ['-1']
location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Storage/locations/westus/asyncoperations/b3183cfc-8f5e-4304-8422-924e23aaa1e4?monitor=true&api-version=2017-06-01']
pragma: [no-cache]
server: [Microsoft-Azure-Storage-Resource-Provider/1.0, Microsoft-HTTPAPI/2.0]
strict-transport-security: [max-age=31536000; includeSubDomains]
x-ms-ratelimit-remaining-subscription-writes: ['1199']
status: {code: 202, message: Accepted}
- request:
body: null
headers:
Accept: [application/json]
Accept-Encoding: ['gzip, deflate']
CommandName: [storage account create]
Connection: [keep-alive]
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.18
msrest_azure/0.4.16 storagemanagementclient/1.4.0 Azure-SDK-For-Python AZURECLI/2.0.21]
accept-language: [en-US]
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Storage/locations/westus/asyncoperations/b3183cfc-8f5e-4304-8422-924e23aaa1e4?monitor=true&api-version=2017-06-01
response:
body: {string: ''}
headers:
cache-control: [no-cache]
content-length: ['0']
date: ['Mon, 13 Nov 2017 18:22:30 GMT']
expires: ['-1']
location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Storage/locations/westus/asyncoperations/b3183cfc-8f5e-4304-8422-924e23aaa1e4?monitor=true&api-version=2017-06-01']
pragma: [no-cache]
server: [Microsoft-Azure-Storage-Resource-Provider/1.0, Microsoft-HTTPAPI/2.0]
strict-transport-security: [max-age=31536000; includeSubDomains]
status: {code: 202, message: Accepted}
- request:
body: null
headers:
Accept: [application/json]
Accept-Encoding: ['gzip, deflate']
CommandName: [storage account create]
Connection: [keep-alive]
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.18
msrest_azure/0.4.16 storagemanagementclient/1.4.0 Azure-SDK-For-Python AZURECLI/2.0.21]
accept-language: [en-US]
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Storage/locations/westus/asyncoperations/b3183cfc-8f5e-4304-8422-924e23aaa1e4?monitor=true&api-version=2017-06-01
response:
body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002","kind":"Storage","location":"westus","name":"clitest000002","properties":{"creationTime":"2017-11-13T18:22:03.5722474Z","encryption":{"keySource":"Microsoft.Storage","services":{"blob":{"enabled":true,"lastEnabledTime":"2017-11-13T18:22:03.6042322Z"},"file":{"enabled":true,"lastEnabledTime":"2017-11-13T18:22:03.6042322Z"}}},"networkAcls":{"bypass":"AzureServices","defaultAction":"Allow","ipRules":[],"virtualNetworkRules":[]},"primaryEndpoints":{"blob":"https://clitest000002.blob.core.windows.net/","file":"https://clitest000002.file.core.windows.net/","queue":"https://clitest000002.queue.core.windows.net/","table":"https://clitest000002.table.core.windows.net/"},"primaryLocation":"westus","provisioningState":"Succeeded","statusOfPrimary":"available","supportsHttpsTrafficOnly":false},"sku":{"name":"Standard_LRS","tier":"Standard"},"tags":{},"type":"Microsoft.Storage/storageAccounts"}
'}
headers:
cache-control: [no-cache]
content-length: ['1170']
content-type: [application/json]
date: ['Mon, 13 Nov 2017 18:22:47 GMT']
expires: ['-1']
pragma: [no-cache]
server: [Microsoft-Azure-Storage-Resource-Provider/1.0, Microsoft-HTTPAPI/2.0]
strict-transport-security: [max-age=31536000; includeSubDomains]
transfer-encoding: [chunked]
vary: [Accept-Encoding]
status: {code: 200, message: OK}
- request:
body: null
headers:
Accept: [application/json]
Accept-Encoding: ['gzip, deflate']
CommandName: [storage account keys list]
Connection: [keep-alive]
Content-Length: ['0']
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.18
msrest_azure/0.4.16 storagemanagementclient/1.4.0 Azure-SDK-For-Python AZURECLI/2.0.21]
accept-language: [en-US]
method: POST
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/listKeys?api-version=2017-06-01
response:
body: {string: '{"keys":[{"keyName":"key1","permissions":"Full","value":"tWFFM0SVLoJRYFzziPGs42xP3wkTPYaoA98xRLOQkKpnY+dFZF22vCU9YOR+NvjIUYjBJP6+CX/hDXuri4W+WQ=="},{"keyName":"key2","permissions":"Full","value":"82ki0XUSk2uT5R4g16VA8bowLwu91yqr7mP3kb9oXb7vAPJGHzttx9is9cVqLvoX3LJfz4dZIRnWcPZclJFEaw=="}]}
'}
headers:
cache-control: [no-cache]
content-length: ['289']
content-type: [application/json]
date: ['Mon, 13 Nov 2017 18:22:49 GMT']
expires: ['-1']
pragma: [no-cache]
server: [Microsoft-Azure-Storage-Resource-Provider/1.0, Microsoft-HTTPAPI/2.0]
strict-transport-security: [max-age=31536000; includeSubDomains]
transfer-encoding: [chunked]
vary: [Accept-Encoding]
x-ms-ratelimit-remaining-subscription-writes: ['1199']
status: {code: 200, message: OK}
- request:
body: null
headers:
Accept: [application/json]
Accept-Encoding: ['gzip, deflate']
CommandName: [storage account show]
Connection: [keep-alive]
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.18
msrest_azure/0.4.16 storagemanagementclient/1.4.0 Azure-SDK-For-Python AZURECLI/2.0.21]
accept-language: [en-US]
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002?api-version=2017-06-01
response:
body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002","kind":"Storage","location":"westus","name":"clitest000002","properties":{"creationTime":"2017-11-13T18:22:03.5722474Z","encryption":{"keySource":"Microsoft.Storage","services":{"blob":{"enabled":true,"lastEnabledTime":"2017-11-13T18:22:03.6042322Z"},"file":{"enabled":true,"lastEnabledTime":"2017-11-13T18:22:03.6042322Z"}}},"networkAcls":{"bypass":"AzureServices","defaultAction":"Allow","ipRules":[],"virtualNetworkRules":[]},"primaryEndpoints":{"blob":"https://clitest000002.blob.core.windows.net/","file":"https://clitest000002.file.core.windows.net/","queue":"https://clitest000002.queue.core.windows.net/","table":"https://clitest000002.table.core.windows.net/"},"primaryLocation":"westus","provisioningState":"Succeeded","statusOfPrimary":"available","supportsHttpsTrafficOnly":false},"sku":{"name":"Standard_LRS","tier":"Standard"},"tags":{},"type":"Microsoft.Storage/storageAccounts"}
'}
headers:
cache-control: [no-cache]
content-length: ['1170']
content-type: [application/json]
date: ['Mon, 13 Nov 2017 18:22:49 GMT']
expires: ['-1']
pragma: [no-cache]
server: [Microsoft-Azure-Storage-Resource-Provider/1.0, Microsoft-HTTPAPI/2.0]
strict-transport-security: [max-age=31536000; includeSubDomains]
transfer-encoding: [chunked]
vary: [Accept-Encoding]
status: {code: 200, message: OK}
- request:
body: null
headers:
Accept: [application/json]
Accept-Encoding: ['gzip, deflate']
CommandName: [monitor metrics list-definitions]
Connection: [keep-alive]
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.18
msrest_azure/0.4.16 monitormanagementclient/0.4.0 Azure-SDK-For-Python AZURECLI/2.0.21]
accept-language: [en-US]
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/providers/microsoft.insights/metricDefinitions?api-version=2017-05-01-preview
response:
body: {string: '{"value":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/providers/microsoft.insights/metricdefinitions/UsedCapacity","resourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002","category":"Capacity","name":{"value":"UsedCapacity","localizedValue":"Used
capacity"},"isDimensionRequired":false,"unit":"Bytes","primaryAggregationType":"Average","metricAvailabilities":[{"timeGrain":"PT1M","retention":"P93D"},{"timeGrain":"PT1H","retention":"P93D"}]},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/providers/microsoft.insights/metricdefinitions/Transactions","resourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002","category":"Transaction","name":{"value":"Transactions","localizedValue":"Transactions"},"isDimensionRequired":false,"unit":"Count","primaryAggregationType":"Total","metricAvailabilities":[{"timeGrain":"PT1M","retention":"P93D"},{"timeGrain":"PT1H","retention":"P93D"}],"dimensions":[{"value":"ResponseType","localizedValue":"Response
type"},{"value":"GeoType","localizedValue":"Geo type"},{"value":"ApiName","localizedValue":"API
name"}]},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/providers/microsoft.insights/metricdefinitions/Ingress","resourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002","category":"Transaction","name":{"value":"Ingress","localizedValue":"Ingress"},"isDimensionRequired":false,"unit":"Bytes","primaryAggregationType":"Total","metricAvailabilities":[{"timeGrain":"PT1M","retention":"P93D"},{"timeGrain":"PT1H","retention":"P93D"}],"dimensions":[{"value":"GeoType","localizedValue":"Geo
type"},{"value":"ApiName","localizedValue":"API name"}]},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/providers/microsoft.insights/metricdefinitions/Egress","resourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002","category":"Transaction","name":{"value":"Egress","localizedValue":"Egress"},"isDimensionRequired":false,"unit":"Bytes","primaryAggregationType":"Total","metricAvailabilities":[{"timeGrain":"PT1M","retention":"P93D"},{"timeGrain":"PT1H","retention":"P93D"}],"dimensions":[{"value":"GeoType","localizedValue":"Geo
type"},{"value":"ApiName","localizedValue":"API name"}]},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/providers/microsoft.insights/metricdefinitions/SuccessServerLatency","resourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002","category":"Transaction","name":{"value":"SuccessServerLatency","localizedValue":"Success
Server Latency"},"isDimensionRequired":false,"unit":"MilliSeconds","primaryAggregationType":"Average","metricAvailabilities":[{"timeGrain":"PT1M","retention":"P93D"},{"timeGrain":"PT1H","retention":"P93D"}],"dimensions":[{"value":"GeoType","localizedValue":"Geo
type"},{"value":"ApiName","localizedValue":"API name"}]},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/providers/microsoft.insights/metricdefinitions/SuccessE2ELatency","resourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002","category":"Transaction","name":{"value":"SuccessE2ELatency","localizedValue":"Success
E2E Latency"},"isDimensionRequired":false,"unit":"MilliSeconds","primaryAggregationType":"Average","metricAvailabilities":[{"timeGrain":"PT1M","retention":"P93D"},{"timeGrain":"PT1H","retention":"P93D"}],"dimensions":[{"value":"GeoType","localizedValue":"Geo
type"},{"value":"ApiName","localizedValue":"API name"}]},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/providers/microsoft.insights/metricdefinitions/Availability","resourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002","category":"Transaction","name":{"value":"Availability","localizedValue":"Availability"},"isDimensionRequired":false,"unit":"Percent","primaryAggregationType":"Average","metricAvailabilities":[{"timeGrain":"PT1M","retention":"P93D"},{"timeGrain":"PT1H","retention":"P93D"}],"dimensions":[{"value":"GeoType","localizedValue":"Geo
type"},{"value":"ApiName","localizedValue":"API name"}]}]}'}
headers:
__handlingserverid__: [shoeboxproxyprod_shoeboxproxyprod-black_MetricsMP_IN_6]
cache-control: [no-cache]
content-length: ['6213']
content-type: [application/json]
date: ['Mon, 13 Nov 2017 18:22:49 GMT']
server: [Microsoft-IIS/8.5]
strict-transport-security: [max-age=31536000; includeSubDomains]
transfer-encoding: [chunked]
vary: ['Accept-Encoding,Accept-Encoding']
x-powered-by: [ASP.NET]
status: {code: 200, message: OK}
- request:
body: null
headers:
Accept: [application/json]
Accept-Encoding: ['gzip, deflate']
CommandName: [group delete]
Connection: [keep-alive]
Content-Length: ['0']
Content-Type: [application/json; charset=utf-8]
User-Agent: [python/3.6.3 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.18
msrest_azure/0.4.16 resourcemanagementclient/1.2.1 Azure-SDK-For-Python
AZURECLI/2.0.21]
accept-language: [en-US]
method: DELETE
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001?api-version=2017-05-10
response:
body: {string: ''}
headers:
cache-control: [no-cache]
content-length: ['0']
date: ['Mon, 13 Nov 2017 18:22:51 GMT']
expires: ['-1']
location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/operationresults/eyJqb2JJZCI6IlJFU09VUkNFR1JPVVBERUxFVElPTkpPQi1DTElURVNUOjJFUkdUTk5SV1c2NjNTTUlaNUhVMkFDTEtCNEhTNjczWjRRN0tCV3xBOEI1NDJGMjk3OEQ1Rjk2LVNPVVRIQ0VOVFJBTFVTIiwiam9iTG9jYXRpb24iOiJzb3V0aGNlbnRyYWx1cyJ9?api-version=2017-05-10']
pragma: [no-cache]
strict-transport-security: [max-age=31536000; includeSubDomains]
x-ms-ratelimit-remaining-subscription-writes: ['1199']
status: {code: 202, message: Accepted}
version: 1

Просмотреть файл

@ -0,0 +1,70 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
import unittest
import re
from azure.cli.core.util import CLIError
from azure.cli.command_modules.monitor.operations.activity_log import (_build_activity_log_odata_filter,
_activity_log_select_filter_builder,
_build_odata_filter)
class TestActivityLogODataBuilderComponents(unittest.TestCase):
def test_build_activity_logs_odata_filter(self):
correlation_id = '1234-34567-56789-34567'
resource_group = 'test'
resource_id = '/subscriptions/xxxx-xxxx-xxxx-xxx/resourceGroups/testrg/providers/Microsoft.Web/sites/testwebapp'
resource_provider = 'Microsoft.Web'
caller = 'contoso@contoso.com'
status = 'RunsSucceeded'
filter_output = _build_activity_log_odata_filter(correlation_id)
regex = r'^(eventTimestamp ge).*(eventTimestamp le).*(correlationId eq).*$'
assert bool(re.search(regex, filter_output))
filter_output = _build_activity_log_odata_filter(resource_group=resource_group)
regex = r'^(eventTimestamp ge).*(eventTimestamp le).*(resourceGroupName eq).*$'
assert bool(re.search(regex, filter_output))
filter_output = _build_activity_log_odata_filter(resource_id=resource_id)
regex = r'^(eventTimestamp ge).*(eventTimestamp le).*(resourceId eq).*$'
assert bool(re.search(regex, filter_output))
filter_output = _build_activity_log_odata_filter(resource_provider=resource_provider)
regex = r'^(eventTimestamp ge).*(eventTimestamp le).*(resourceProvider eq).*$'
assert bool(re.search(regex, filter_output))
filter_output = _build_activity_log_odata_filter(caller=caller)
regex = r'^(eventTimestamp ge).*(eventTimestamp le).*(caller eq).*$'
assert bool(re.search(regex, filter_output))
filter_output = _build_activity_log_odata_filter(status=status)
regex = r'^(eventTimestamp ge).*(eventTimestamp le).*(status eq).*$'
assert bool(re.search(regex, filter_output))
def test_activity_logs_select_filter_builder(self):
select_output = _activity_log_select_filter_builder()
assert select_output is None
events = ['channels']
select_output = _activity_log_select_filter_builder(events)
assert select_output == '{}'.format(events[0])
events = ['eventDataId', 'eventSource']
select_output = _activity_log_select_filter_builder(events)
assert select_output == '{} , {}'.format(events[0], events[1])
def test_build_odata_filter(self):
default_filter = "timeGrain eq duration'PT1M'"
field_name = 'correlation_id'
field_value = '1234-34567-56789-34567'
field_label = 'correlationId'
filter_output = _build_odata_filter(default_filter, field_name, field_value, field_label)
regex = r'^({} and {} eq \'{}\')$'.format(default_filter, field_label, field_value)
assert bool(re.search(regex, filter_output))
with self.assertRaises(CLIError):
_build_odata_filter(default_filter, field_name, None, field_label)

Просмотреть файл

@ -0,0 +1,23 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
from time import sleep
from azure.cli.testsdk import LiveScenarioTest, ResourceGroupPreparer, StorageAccountPreparer
# This is a live test because the start and end time can't be determined dynamically
class TestActivityLogScenarios(LiveScenarioTest):
@ResourceGroupPreparer(location='southcentralus')
@StorageAccountPreparer()
def test_activity_log_list_scenario(self, resource_group):
for count in range(3):
logs = self.cmd('monitor activity-log list --resource-group {}'.format(resource_group)).get_output_in_json()
if len(logs) > 0:
break
sleep(2 ** count) # Wait 1, 2, and 4 seconds incrementally to let the activity log catch up.
else:
self.assertTrue(False, 'After three try the command fails to retrieve any activity log.')

Просмотреть файл

@ -1,175 +0,0 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
import unittest
try:
import unittest.mock as mock
except ImportError:
import mock
import re
from knack.util import CLIError
from azure.cli.command_modules.monitor.custom import (_metric_names_filter_builder,
_metrics_odata_filter_builder,
_build_activity_log_odata_filter,
_activity_log_select_filter_builder,
_build_odata_filter,
scaffold_autoscale_settings_parameters)
class FilterBuilderTests(unittest.TestCase):
def test_metric_names_filter_builder(self):
metric_names = None
filter_output = _metric_names_filter_builder(metric_names)
assert filter_output == ''
metric_names = ['ActionsCompleted']
filter_output = _metric_names_filter_builder(metric_names)
assert filter_output == "name.value eq '{}'".format(metric_names[0])
metric_names = ['RunsSucceeded', 'ActionsCompleted']
filter_output = _metric_names_filter_builder(metric_names)
assert filter_output == 'name.value eq \'{}\' or name.value eq \'{}\''.format(
metric_names[0], metric_names[1])
def test_metrics_odata_filter_builder(self):
filter_output = _metrics_odata_filter_builder('PT1M')
regex = r'^(timeGrain eq duration).*(startTime eq).*(endTime eq).*$'
assert bool(re.search(regex, filter_output))
filter_output = _metrics_odata_filter_builder('PT1M', '1970-01-01T00:00:00Z')
assert bool(re.search(regex, filter_output))
filter_output = _metrics_odata_filter_builder('PT1M', end_time='1970-01-01T00:00:00Z')
assert bool(re.search(regex, filter_output))
metric_names = ['ActionsCompleted']
regex = r'^(\(name.value eq).*(timeGrain eq duration).*(startTime eq).*(endTime eq).*$'
filter_output = _metrics_odata_filter_builder('PT1M', metric_names=metric_names)
assert bool(re.search(regex, filter_output))
def test_build_activity_logs_odata_filter(self):
correlation_id = '1234-34567-56789-34567'
resource_group = 'test'
resource_id = '/subscriptions/xxxx-xxxx-xxxx-xxx/resourceGroups/testrg/providers/' \
'Microsoft.Web/sites/testwebapp'
resource_provider = 'Microsoft.Web'
caller = 'contoso@contoso.com'
status = 'RunsSucceeded'
filter_output = _build_activity_log_odata_filter(correlation_id)
regex = r'^(eventTimestamp ge).*(eventTimestamp le).*(correlationId eq).*$'
assert bool(re.search(regex, filter_output))
filter_output = _build_activity_log_odata_filter(resource_group=resource_group)
regex = r'^(eventTimestamp ge).*(eventTimestamp le).*(resourceGroupName eq).*$'
assert bool(re.search(regex, filter_output))
filter_output = _build_activity_log_odata_filter(resource_id=resource_id)
regex = r'^(eventTimestamp ge).*(eventTimestamp le).*(resourceId eq).*$'
assert bool(re.search(regex, filter_output))
filter_output = _build_activity_log_odata_filter(resource_provider=resource_provider)
regex = r'^(eventTimestamp ge).*(eventTimestamp le).*(resourceProvider eq).*$'
assert bool(re.search(regex, filter_output))
filter_output = _build_activity_log_odata_filter(caller=caller)
regex = r'^(eventTimestamp ge).*(eventTimestamp le).*(caller eq).*$'
assert bool(re.search(regex, filter_output))
filter_output = _build_activity_log_odata_filter(status=status)
regex = r'^(eventTimestamp ge).*(eventTimestamp le).*(status eq).*$'
assert bool(re.search(regex, filter_output))
def test_activity_logs_select_filter_builder(self):
select_output = _activity_log_select_filter_builder()
assert select_output is None
events = ['channels']
select_output = _activity_log_select_filter_builder(events)
assert select_output == '{}'.format(events[0])
events = ['eventDataId', 'eventSource']
select_output = _activity_log_select_filter_builder(events)
assert select_output == '{} , {}'.format(events[0], events[1])
def test_build_odata_filter(self):
default_filter = "timeGrain eq duration'PT1M'"
field_name = 'correlation_id'
field_value = '1234-34567-56789-34567'
field_label = 'correlationId'
filter_output = _build_odata_filter(default_filter, field_name, field_value, field_label)
regex = r'^({} and {} eq \'{}\')$'.format(default_filter, field_label, field_value)
assert bool(re.search(regex, filter_output))
with self.assertRaises(CLIError):
_build_odata_filter(default_filter, field_name, None, field_label)
def test_scaffold_autoscale_settings_parameters(self):
template = scaffold_autoscale_settings_parameters(None)
if not template or not isinstance(template, dict):
assert False
def _mock_get_subscription_id():
return '00000000-0000-0000-0000-000000000000'
class MonitorNameOrIdTest(unittest.TestCase):
def _build_namespace(self, name_or_id=None, resource_group=None, provider_namespace=None, parent=None, resource_type=None):
from argparse import Namespace
ns = Namespace()
ns.name_or_id = name_or_id
ns.resource_group_name = resource_group
ns.namespace = provider_namespace
ns.parent = parent
ns.resource_type = resource_type
return ns
@mock.patch('azure.cli.core.commands.client_factory.get_subscription_id', _mock_get_subscription_id)
def test_monitor_resource_id(self):
from azure.cli.command_modules.monitor.validators import get_target_resource_validator
validator = get_target_resource_validator('name_or_id', True)
id = '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/my-rg/providers/Microsoft.Compute/virtualMachines/vm1'
# must supply name or ID
ns = self._build_namespace()
with self.assertRaises(CLIError):
validator(ns)
# must only supply ID or name parameters
ns = self._build_namespace(id, 'my-rg', 'blahblah', 'stuff')
with self.assertRaises(CLIError):
validator(ns)
# error on invalid ID
ns = self._build_namespace('bad-id')
with self.assertRaises(CLIError):
validator(ns)
# allow Provider/Type syntax (same as resource commands)
ns = self._build_namespace('vm1', 'my-rg', None, None, 'Microsoft.Compute/virtualMachines')
validator(ns)
self.assertEqual(ns.name_or_id, id)
# allow Provider and Type separate
ns = self._build_namespace('vm1', 'my-rg', 'Microsoft.Compute', None, 'virtualMachines')
validator(ns)
self.assertEqual(ns.name_or_id, id)
# verify works with parent
id = '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/my-rg/providers/Microsoft.Compute/fakeType/type1/anotherFakeType/type2/virtualMachines/vm1'
ns = self._build_namespace('vm1', 'my-rg', 'Microsoft.Compute', 'fakeType/type1/anotherFakeType/type2', 'virtualMachines')
validator(ns)
self.assertEqual(ns.name_or_id, id)
# verify extra parameters are removed
self.assertFalse(hasattr(ns, 'resource_name'))
self.assertFalse(hasattr(ns, 'namespace'))
self.assertFalse(hasattr(ns, 'parent'))
self.assertFalse(hasattr(ns, 'resource_type'))

Просмотреть файл

@ -1,105 +0,0 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
import unittest
from azure.cli.testsdk import ScenarioTest, JMESPathCheck, ResourceGroupPreparer
class MonitorTests(ScenarioTest):
@ResourceGroupPreparer(name_prefix='cli_test_monitor')
def test_monitor(self, resource_group):
vm = 'vm1'
vm_json = self.cmd('vm create -g {} -n {} --image UbuntuLTS --admin-password TestPassword11!! --admin-username testadmin --authentication-type password'.format(resource_group, vm)).get_output_in_json()
vm_id = vm_json['id']
# catalog command--so just don't fail
self.cmd('monitor metrics list-definitions --resource {} -g {} --resource-type Microsoft.Compute/virtualMachines'.format(vm, resource_group))
# test alert commands
rule1 = 'rule1'
rule2 = 'rule2'
rule3 = 'rule3'
webhook1 = 'https://alert.contoso.com?apiKey=value'
webhook2 = 'https://contoso.com/alerts'
self.cmd('monitor alert create -g {} -n {} --target {} --condition "Percentage CPU > 90 avg 5m"'.format(resource_group, rule1, vm_id), checks=[
JMESPathCheck('actions[0].customEmails', []),
JMESPathCheck('actions[0].sendToServiceOwners', False),
JMESPathCheck('alertRuleResourceName', rule1),
JMESPathCheck('condition.dataSource.metricName', 'Percentage CPU'),
JMESPathCheck('condition.dataSource.resourceUri', vm_id),
JMESPathCheck('condition.threshold', 90.0),
JMESPathCheck('condition.timeAggregation', 'Average'),
JMESPathCheck('condition.windowSize', '0:05:00'),
])
self.cmd('monitor alert create -g {} -n {} --target {} --target-namespace Microsoft.Compute --target-type virtualMachines --disabled --condition "Percentage CPU >= 60 avg 1h" --description "Test Rule 2" -a email test1@contoso.com test2@contoso.com test3@contoso.com'.format(resource_group, rule2, vm), checks=[
JMESPathCheck('length(actions[0].customEmails)', 3),
JMESPathCheck('actions[0].sendToServiceOwners', False),
JMESPathCheck('alertRuleResourceName', rule2),
JMESPathCheck('condition.dataSource.metricName', 'Percentage CPU'),
JMESPathCheck('condition.dataSource.resourceUri', vm_id),
JMESPathCheck('condition.threshold', 60.0),
JMESPathCheck('condition.timeAggregation', 'Average'),
JMESPathCheck('condition.windowSize', '1:00:00'),
JMESPathCheck('isEnabled', False),
JMESPathCheck('description', 'Test Rule 2')
])
self.cmd('monitor alert create -g {} -n {} --target {} --condition "Percentage CPU >= 99 avg 5m" --action webhook {} --action webhook {} apiKey=value'.format(resource_group, rule3, vm_id, webhook1, webhook2), checks=[
JMESPathCheck('alertRuleResourceName', rule3),
JMESPathCheck('condition.dataSource.metricName', 'Percentage CPU'),
JMESPathCheck('condition.dataSource.resourceUri', vm_id),
JMESPathCheck('condition.operator', 'GreaterThanOrEqual'),
JMESPathCheck('condition.threshold', 99.0),
JMESPathCheck('condition.timeAggregation', 'Average'),
JMESPathCheck('condition.windowSize', '0:05:00'),
JMESPathCheck('isEnabled', True),
JMESPathCheck('description', 'Percentage CPU >= 99 avg 5m')
])
self.cmd('monitor alert show -g {} -n {}'.format(resource_group, rule1), checks=[
JMESPathCheck('alertRuleResourceName', rule1)
])
self.cmd('monitor alert delete -g {} -n {}'.format(resource_group, rule2))
self.cmd('monitor alert delete -g {} -n {}'.format(resource_group, rule3))
self.cmd('monitor alert list -g {}'.format(resource_group), checks=[
JMESPathCheck('length(@)', 1)
])
def _check_emails(actions, emails_to_verify, email_service_owners=None):
emails = next((x for x in actions if x['odatatype'].endswith('RuleEmailAction')), None)
custom_emails = emails['customEmails']
if emails_to_verify is not None:
self.assertEqual(str(emails_to_verify.sort()), str(custom_emails.sort()))
if email_service_owners is not None:
self.assertEqual(emails['sendToServiceOwners'], email_service_owners)
def _check_webhooks(actions, uris_to_check):
webhooks = [x['serviceUri'] for x in actions if x['odatatype'].endswith('RuleWebhookAction')]
if uris_to_check is not None:
self.assertEqual(webhooks.sort(), uris_to_check.sort())
# test updates
result = self.cmd('monitor alert update -g {} -n {} -a email test1@contoso.com -a webhook {} --operator ">=" --threshold 85'.format(resource_group, rule1, webhook1), checks=[
JMESPathCheck('condition.operator', 'GreaterThanOrEqual'),
JMESPathCheck('condition.threshold', 85.0),
]).get_output_in_json()
_check_emails(result['actions'], ['test1@contoso.com'], None)
_check_webhooks(result['actions'], [webhook1])
result = self.cmd('monitor alert update -g {} -n {} -r email test1@contoso.com -a email test2@contoso.com -a email test3@contoso.com'.format(resource_group, rule1)).get_output_in_json()
_check_emails(result['actions'], ['test1@contoso.com', 'test2@contoso.com', 'test3@contoso.com'], None)
result = self.cmd('monitor alert update -g {} -n {} --email-service-owners'.format(resource_group, rule1)).get_output_in_json()
_check_emails(result['actions'], None, True)
self.cmd('monitor alert update -g {} -n {} --email-service-owners False --remove-action webhook {} --add-action webhook {}'.format(resource_group, rule1, webhook1, webhook2))
_check_webhooks(result['actions'], [webhook2])
if __name__ == '__main__':
unittest.main()

Просмотреть файл

@ -44,7 +44,7 @@ class TestActionGroupScenarios(ScenarioTest):
JMESPathCheck('length(webhookReceivers)', 0)])
self.cmd('monitor action-group enable-receiver -n nonexist --action-group {} -g {}'
.format(action_group_name, resource_group))
.format(action_group_name, resource_group), expect_failure=True)
self.cmd('monitor action-group enable-receiver -n alice --action-group {} -g {}'
.format(action_group_name, resource_group))

Просмотреть файл

@ -0,0 +1,111 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
from azure.cli.testsdk import ScenarioTest, JMESPathCheck, ResourceGroupPreparer
class MonitorTests(ScenarioTest):
@ResourceGroupPreparer(name_prefix='cli_test_monitor')
def test_metric_alert_basic_scenarios(self, resource_group):
vm = 'vm1'
vm_json = self.cmd('vm create -g {} -n {} --image UbuntuLTS --admin-password TestPassword11!! --admin-username '
'testadmin --authentication-type password'.format(resource_group, vm)).get_output_in_json()
vm_id = vm_json['id']
# test alert commands
rule1 = 'rule1'
rule2 = 'rule2'
rule3 = 'rule3'
webhook1 = 'https://alert.contoso.com?apiKey=value'
webhook2 = 'https://contoso.com/alerts'
self.cmd('monitor alert create -g {} -n {} --target {} --condition "Percentage CPU > 90 avg 5m"'
.format(resource_group, rule1, vm_id),
checks=[
JMESPathCheck('actions[0].customEmails', []),
JMESPathCheck('actions[0].sendToServiceOwners', False),
JMESPathCheck('alertRuleResourceName', rule1),
JMESPathCheck('condition.dataSource.metricName', 'Percentage CPU'),
JMESPathCheck('condition.dataSource.resourceUri', vm_id),
JMESPathCheck('condition.threshold', 90.0),
JMESPathCheck('condition.timeAggregation', 'Average'),
JMESPathCheck('condition.windowSize', '0:05:00')
])
self.cmd('monitor alert create -g {} -n {} --target {} --target-namespace Microsoft.Compute '
'--target-type virtualMachines --disabled --condition "Percentage CPU >= 60 avg 1h" '
'--description "Test Rule 2" -a email test1@contoso.com test2@contoso.com test3@contoso.com'
.format(resource_group, rule2, vm),
checks=[
JMESPathCheck('length(actions[0].customEmails)', 3),
JMESPathCheck('actions[0].sendToServiceOwners', False),
JMESPathCheck('alertRuleResourceName', rule2),
JMESPathCheck('condition.dataSource.metricName', 'Percentage CPU'),
JMESPathCheck('condition.dataSource.resourceUri', vm_id),
JMESPathCheck('condition.threshold', 60.0),
JMESPathCheck('condition.timeAggregation', 'Average'),
JMESPathCheck('condition.windowSize', '1:00:00'),
JMESPathCheck('isEnabled', False),
JMESPathCheck('description', 'Test Rule 2')
])
self.cmd('monitor alert create -g {} -n {} --target {} --condition "Percentage CPU >= 99 avg 5m" '
'--action webhook {} --action webhook {} apiKey=value'
.format(resource_group, rule3, vm_id, webhook1, webhook2),
checks=[
JMESPathCheck('alertRuleResourceName', rule3),
JMESPathCheck('condition.dataSource.metricName', 'Percentage CPU'),
JMESPathCheck('condition.dataSource.resourceUri', vm_id),
JMESPathCheck('condition.operator', 'GreaterThanOrEqual'),
JMESPathCheck('condition.threshold', 99.0),
JMESPathCheck('condition.timeAggregation', 'Average'),
JMESPathCheck('condition.windowSize', '0:05:00'),
JMESPathCheck('isEnabled', True),
JMESPathCheck('description', 'Percentage CPU >= 99 avg 5m')
])
self.cmd('monitor alert show -g {} -n {}'.format(resource_group, rule1), checks=[
JMESPathCheck('alertRuleResourceName', rule1)
])
self.cmd('monitor alert delete -g {} -n {}'.format(resource_group, rule2))
self.cmd('monitor alert delete -g {} -n {}'.format(resource_group, rule3))
self.cmd('monitor alert list -g {}'.format(resource_group), checks=[JMESPathCheck('length(@)', 1)])
def _check_emails(actions, emails_to_verify, email_service_owners=None):
emails = next((x for x in actions if x['odatatype'].endswith('RuleEmailAction')), None)
custom_emails = emails['customEmails']
if emails_to_verify is not None:
self.assertEqual(str(emails_to_verify.sort()), str(custom_emails.sort()))
if email_service_owners is not None:
self.assertEqual(emails['sendToServiceOwners'], email_service_owners)
def _check_webhooks(actions, uris_to_check):
webhooks = [x['serviceUri'] for x in actions if x['odatatype'].endswith('RuleWebhookAction')]
if uris_to_check is not None:
self.assertEqual(webhooks.sort(), uris_to_check.sort())
# test updates
result = self.cmd('monitor alert update -g {} -n {} -a email test1@contoso.com -a webhook {} --operator ">=" '
'--threshold 85'.format(resource_group, rule1, webhook1),
checks=[
JMESPathCheck('condition.operator', 'GreaterThanOrEqual'),
JMESPathCheck('condition.threshold', 85.0),
]).get_output_in_json()
_check_emails(result['actions'], ['test1@contoso.com'], None)
_check_webhooks(result['actions'], [webhook1])
result = self.cmd('monitor alert update -g {} -n {} -r email test1@contoso.com -a email test2@contoso.com '
'-a email test3@contoso.com'.format(resource_group, rule1)).get_output_in_json()
_check_emails(result['actions'], ['test1@contoso.com', 'test2@contoso.com', 'test3@contoso.com'], None)
result = self.cmd('monitor alert update -g {} -n {} --email-service-owners'
.format(resource_group, rule1)).get_output_in_json()
_check_emails(result['actions'], None, True)
self.cmd('monitor alert update -g {} -n {} --email-service-owners False --remove-action webhook {} '
'--add-action webhook {}'.format(resource_group, rule1, webhook1, webhook2))
_check_webhooks(result['actions'], [webhook2])
if __name__ == '__main__':
import unittest
unittest.main()

Просмотреть файл

@ -0,0 +1,16 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
from azure.cli.testsdk import ScenarioTest, ResourceGroupPreparer, StorageAccountPreparer
class TestMonitorMetrics(ScenarioTest):
@ResourceGroupPreparer(location='southcentralus')
@StorageAccountPreparer()
def test_monitor_metrics(self, resource_group, storage_account):
resource_id = self.cmd(
'az storage account show -n {} -g {} --query id -otsv'.format(storage_account, resource_group)).output
self.cmd('az monitor metrics list-definitions --resource {}'.format(resource_id))

Просмотреть файл

@ -0,0 +1,85 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
import unittest
try:
import unittest.mock as mock
except ImportError:
import mock
from azure.cli.core.util import CLIError
from azure.cli.command_modules.monitor.operations.autoscale_settings import scaffold_autoscale_settings_parameters
class FilterBuilderTests(unittest.TestCase):
def test_scaffold_autoscale_settings_parameters(self):
template = scaffold_autoscale_settings_parameters(None)
self.assertTrue(template)
self.assertTrue(isinstance(template, dict))
def _mock_get_subscription_id():
return '00000000-0000-0000-0000-000000000000'
class MonitorNameOrIdTest(unittest.TestCase):
def _build_namespace(self, name_or_id=None, resource_group=None, provider_namespace=None, parent=None,
resource_type=None):
from argparse import Namespace
ns = Namespace()
ns.name_or_id = name_or_id
ns.resource_group_name = resource_group
ns.namespace = provider_namespace
ns.parent = parent
ns.resource_type = resource_type
return ns
@mock.patch('azure.cli.core.commands.client_factory.get_subscription_id', _mock_get_subscription_id)
def test_monitor_resource_id(self):
from azure.cli.command_modules.monitor.validators import get_target_resource_validator
validator = get_target_resource_validator('name_or_id', True)
id = '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/my-rg/providers/Microsoft.Compute/' \
'virtualMachines/vm1'
# must supply name or ID
ns = self._build_namespace()
with self.assertRaises(CLIError):
validator(ns)
# must only supply ID or name parameters
ns = self._build_namespace(id, 'my-rg', 'blahblah', 'stuff')
with self.assertRaises(CLIError):
validator(ns)
# error on invalid ID
ns = self._build_namespace('bad-id')
with self.assertRaises(CLIError):
validator(ns)
# allow Provider/Type syntax (same as resource commands)
ns = self._build_namespace('vm1', 'my-rg', None, None, 'Microsoft.Compute/virtualMachines')
validator(ns)
self.assertEqual(ns.name_or_id, id)
# allow Provider and Type separate
ns = self._build_namespace('vm1', 'my-rg', 'Microsoft.Compute', None, 'virtualMachines')
validator(ns)
self.assertEqual(ns.name_or_id, id)
# verify works with parent
id = '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/my-rg/providers/Microsoft.Compute/' \
'fakeType/type1/anotherFakeType/type2/virtualMachines/vm1'
ns = self._build_namespace('vm1', 'my-rg', 'Microsoft.Compute', 'fakeType/type1/anotherFakeType/type2',
'virtualMachines')
validator(ns)
self.assertEqual(ns.name_or_id, id)
# verify extra parameters are removed
self.assertFalse(hasattr(ns, 'resource_name'))
self.assertFalse(hasattr(ns, 'namespace'))
self.assertFalse(hasattr(ns, 'parent'))
self.assertFalse(hasattr(ns, 'resource_type'))

Просмотреть файл

@ -28,6 +28,13 @@ def _item_to_ordered_dict(item, *properties):
return result
def _generic_table_convert(source, row_convert_fn):
if not isinstance(source, list):
source = [source]
return [row_convert_fn(each) for each in source]
def action_group_list_table(results):
if not isinstance(results, list):
results = [results]
@ -35,10 +42,56 @@ def action_group_list_table(results):
output_results = []
for result in results:
data = _item_to_ordered_dict(result, 'name', 'resourceGroup', 'groupShortName', 'enabled', 'location',
('emailReceivers', 'email'),
('smsReceivers', 'sms'),
('emailReceivers', 'email'), ('smsReceivers', 'sms'),
('webhookReceivers', 'webhook'))
output_results.append(data)
return output_results
def metrics_definitions_table(results):
def row_convert(item):
from collections import OrderedDict
result = OrderedDict()
result['Display Name'] = item['name']['localizedValue']
result['Metric Name'] = item['name']['value']
result['Unit'] = item['unit']
result['Type'] = item['primaryAggregationType']
result['Dimension Required'] = 'True' if item['isDimensionRequired'] else 'False'
result['Dimensions'] = ', '.join(d['value'] for d in item.get('dimensions', []) or [])
return result
return _generic_table_convert(results, row_convert)
def metrics_table(results):
from collections import OrderedDict
def from_time(time_string):
from datetime import datetime
try:
return datetime.strptime(time_string, '%Y-%m-%dT%H:%M:%S+00:00').strftime('%Y-%m-%d %H:%M:%S')
except ValueError:
return time_string
retval = []
for value_group in results['value']:
name = value_group['name']['localizedValue']
for series in value_group['timeseries']:
metadata = dict((m['name']['localizedValue'], m['value']) for m in series['metadatavalues'])
for data in series['data']:
row = OrderedDict()
row['Timestamp'] = from_time(data['timeStamp'])
row['Name'] = name
for metadata_name, metadata_value in metadata.items():
row[metadata_name] = metadata_value
for field in data:
if field == 'timeStamp':
continue
row[field] = data[field]
retval.append(row)
return retval

Просмотреть файл

@ -3,6 +3,11 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
from datetime import datetime, timedelta
# ISO format with explicit indication of timezone
DATE_TIME_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
def get_resource_group_location(name):
from azure.cli.core.commands.client_factory import get_mgmt_service_client
@ -10,3 +15,32 @@ def get_resource_group_location(name):
# pylint: disable=no-member
return get_mgmt_service_client(ResourceType.MGMT_RESOURCE_RESOURCES).resource_groups.get(name).location
def get_operator_map():
from azure.mgmt.monitor.models import ConditionOperator
return {'>': ConditionOperator.greater_than.value, '>=': ConditionOperator.greater_than_or_equal.value,
'<': ConditionOperator.less_than, '<=': ConditionOperator.less_than_or_equal}
def get_aggregation_map():
from azure.mgmt.monitor.models import TimeAggregationOperator
return {'avg': TimeAggregationOperator.average.value, 'min': TimeAggregationOperator.minimum.value,
'max': TimeAggregationOperator.maximum.value, 'total': TimeAggregationOperator.total.value,
'last': TimeAggregationOperator.last.value}
def validate_time_range_and_add_defaults(start_time, end_time, formatter='startTime eq {} and endTime eq {}'):
try:
end_time = datetime.strptime(end_time, DATE_TIME_FORMAT) if end_time else datetime.utcnow()
except ValueError:
raise ValueError("Input '{}' is not valid datetime. Valid example: 2000-12-31T12:59:59Z".format(end_time))
try:
start_time = datetime.strptime(start_time, DATE_TIME_FORMAT) if start_time else end_time - timedelta(hours=1)
if start_time >= end_time:
raise ValueError("Start time cannot be later than end time.")
except ValueError:
raise ValueError("Input '{}' is not valid datetime. Valid example: 2000-12-31T12:59:59Z".format(start_time))
return formatter.format(start_time.strftime('%Y-%m-%dT%H:%M:%SZ'), end_time.strftime('%Y-%m-%dT%H:%M:%SZ'))

Просмотреть файл

@ -7,7 +7,7 @@ from azure.cli.core.commands.arm import is_valid_resource_id, resource_id, parse
from knack.util import CLIError
def get_target_resource_validator(dest, required):
def get_target_resource_validator(dest, required, preserve_resource_group_parameter=False):
def _validator(namespace):
name_or_id = getattr(namespace, dest)
rg = namespace.resource_group_name
@ -39,6 +39,8 @@ def get_target_resource_validator(dest, required):
del namespace.namespace
del namespace.parent
del namespace.resource_type
if not preserve_resource_group_parameter:
del namespace.resource_group_name
return _validator
@ -129,3 +131,42 @@ def process_action_group_detail_for_creation(namespace):
}
ns['action_group'] = ActionGroupResource(**action_group_resource_properties)
def process_metric_timespan(namespace):
from .util import validate_time_range_and_add_defaults
ns = vars(namespace)
start_time = ns.pop('start_time', None)
end_time = ns.pop('end_time', None)
ns['timespan'] = validate_time_range_and_add_defaults(start_time, end_time, formatter='{}/{}')
def process_metric_aggregation(namespace):
ns = vars(namespace)
aggregation = ns.pop('aggregation', None)
if aggregation:
ns['aggregation'] = ','.join(aggregation)
def process_metric_result_type(namespace):
from azure.mgmt.monitor.models.monitor_management_client_enums import ResultType
ns = vars(namespace)
metadata_only = ns.pop('metadata', False)
if metadata_only:
ns['result_type'] = ResultType.metadata
def process_metric_dimension(namespace):
ns = vars(namespace)
dimensions = ns.pop('dimension', None)
if not dimensions:
return
param_filter = ns.pop('filter', None)
if param_filter:
raise CLIError('usage: --dimension and --filter parameters are mutually exclusive.')
ns['filter'] = ' and '.join("{} eq '*'".format(d) for d in dimensions)

Просмотреть файл

@ -12,7 +12,7 @@ except ImportError:
logger.warn("Wheel is not available, disabling bdist_wheel hook")
cmdclass = {}
VERSION = "0.0.12"
VERSION = "0.0.13"
CLASSIFIERS = [
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
@ -29,8 +29,7 @@ CLASSIFIERS = [
DEPENDENCIES = [
'azure-cli-core',
'azure-monitor==0.3.0',
'azure-mgmt-monitor==0.3.0',
'azure-mgmt-monitor==0.4.0',
'azure-mgmt-resource==1.2.1'
]
@ -53,9 +52,10 @@ setup(
'azure',
'azure.cli',
'azure.cli.command_modules',
'azure.cli.command_modules.monitor'
'azure.cli.command_modules.monitor',
'azure.cli.command_modules.monitor.operations'
],
package_data={'azure.cli.command_modules.monitor': ['autoscale-parameters-template.json']},
package_data={'azure.cli.command_modules.monitor.operations': ['autoscale-parameters-template.json']},
install_requires=DEPENDENCIES,
cmdclass=cmdclass
)