diff --git a/azure-cli2017.pyproj b/azure-cli2017.pyproj index 680560b71d8..2d32cbfd73f 100644 --- a/azure-cli2017.pyproj +++ b/azure-cli2017.pyproj @@ -558,19 +558,18 @@ + - - diff --git a/src/azure-cli-core/azure/cli/core/commands/parameters.py b/src/azure-cli-core/azure/cli/core/commands/parameters.py index d49ade54bd1..a136b89d848 100644 --- a/src/azure-cli-core/azure/cli/core/commands/parameters.py +++ b/src/azure-cli-core/azure/cli/core/commands/parameters.py @@ -36,7 +36,7 @@ def get_location_completion_list(cmd, prefix, namespace, **kwargs): # pylint: d # pylint: disable=redefined-builtin def get_datetime_type(help=None, date=True, time=True, timezone=True): - help_string = help + ' ' or '' + help_string = help + ' ' if help else '' accepted_formats = [] if date: accepted_formats.append('date (yyyy-mm-dd)') @@ -44,7 +44,7 @@ def get_datetime_type(help=None, date=True, time=True, timezone=True): accepted_formats.append('time (hh:mm:ss.xxxxx)') if timezone: accepted_formats.append('timezone (+/-hh:mm)') - help_string = help_string + 'Format: ' + ', '.join(accepted_formats) + help_string = help_string + 'Format: ' + ' '.join(accepted_formats) # pylint: disable=too-few-public-methods class DatetimeAction(argparse.Action): @@ -52,6 +52,7 @@ class DatetimeAction(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): """ Parse a date value and return the ISO8601 string. """ import dateutil.parser + import dateutil.tz value_string = ' '.join(values) dt_val = None @@ -62,10 +63,12 @@ def __call__(self, parser, namespace, values, option_string=None): pass # TODO: custom parsing attempts here - if not dt_val: raise CLIError("Unable to parse: '{}'. Expected format: {}".format(value_string, help_string)) + if not dt_val.tzinfo and timezone: + dt_val = dt_val.replace(tzinfo=dateutil.tz.tzlocal()) + # Issue warning if any supplied data will be ignored if not date and any([dt_val.day, dt_val.month, dt_val.year]): logger.warning('Date info will be ignored in %s.', value_string) diff --git a/src/command_modules/azure-cli-monitor/HISTORY.rst b/src/command_modules/azure-cli-monitor/HISTORY.rst index 673e498aabf..b6191578c71 100644 --- a/src/command_modules/azure-cli-monitor/HISTORY.rst +++ b/src/command_modules/azure-cli-monitor/HISTORY.rst @@ -5,6 +5,15 @@ Release History 0.2.5 +++++ +* `monitor activity-log list`: + Allow listing all events at the subscription level. + Added `--offset` parameter to more easily create time queries. + Improved validation for --start-time and --end-time to use wider range of ISO8601 formats and more user-friendly datetime formats. + Added `--namespace` as alias for deprecated option `--resource-provider`. + Deprecated `--filters` because no values other than those with strongly-typed options are supported by the service. +* `monitor metrics list`: + Added `--offset` parameter to more easily create time queries. + Improved validation for --start-time and --end-time to use wider range of ISO8601 formats and more user-friendly datetime formats. * `monitor diagnostic-settings create`: Improve validation for arguments `--event-hub` and `--event-hub-rule`. 0.2.4 diff --git a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/__init__.py b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/__init__.py index 34b9f847dc9..8904bc1dd47 100644 --- a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/__init__.py +++ b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/__init__.py @@ -4,7 +4,7 @@ # -------------------------------------------------------------------------------------------- from azure.cli.core import AzCommandsLoader -from azure.cli.core.commands import AzArgumentContext +from azure.cli.core.commands import AzArgumentContext, CliCommandType from azure.cli.command_modules.monitor._help import helps # pylint: disable=unused-import @@ -32,9 +32,14 @@ def resource_parameter(self, dest, arg_group=None, required=True, skip_validator class MonitorCommandsLoader(AzCommandsLoader): def __init__(self, cli_ctx=None): + from azure.cli.command_modules.monitor._exception_handler import monitor_exception_handler + monitor_custom = CliCommandType( + operations_tmpl='azure.cli.command_modules.monitor.custom#{}', + exception_handler=monitor_exception_handler) super(MonitorCommandsLoader, self).__init__(cli_ctx=cli_ctx, min_profile='2017-03-10-profile', - argument_context_cls=MonitorArgumentContext) + argument_context_cls=MonitorArgumentContext, + custom_command_type=monitor_custom) def load_command_table(self, args): from azure.cli.command_modules.monitor.commands import load_command_table diff --git a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/_help.py b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/_help.py index 72b276debfe..2ba92625235 100644 --- a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/_help.py +++ b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/_help.py @@ -133,30 +133,27 @@ 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 the current time. + The interval over which to aggregate metrics, in ##h##m format. - name: --filter - type: string short-summary: A string used to reduce the set of metric data returned. eg. "BlobType eq '*'" long-summary: 'For a full list of filters, see the filter string reference at https://docs.microsoft.com/en-us/rest/api/monitor/metrics/list' - 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. + - name: --namespace + short-summary: Namespace to query metric definitions for. + - name: --offset + short-summary: > + Time offset of the query range, in ##d##h format. + long-summary: > + Can be used with either --start-time or --end-time. If used with --start-time, then + the end time will be calculated by adding the offset. If used with --end-time (default), then + the start time will be calculated by subtracting the offset. If --start-time and --end-time are + provided, then --offset will be ignored. examples: - name: List a VM's CPU usage for the past hour text: > @@ -822,37 +819,38 @@ helps['monitor activity-log list'] = """ type: command - short-summary: List events from the activity log. + short-summary: List and query activity log events. parameters: - - name: --filters - short-summary: > - The OData filter for the list activity logs. If this argument is provided OData Filter - Arguments will be ignored. - name: --correlation-id - short-summary: Correlation ID of the query. - - name: --resource-group - short-summary: Resource group to query. + short-summary: Correlation ID to query. - name: --resource-id - short-summary: Identifier of the resource. - - name: --resource-provider - short-summary: Resource provider - - name: --start-time - short-summary: > - Start time of the query. 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 - short-summary: > - End time of the query. ISO format with explicit indication of timezone: 1970-01-01T00:00:00Z, - 1970-01-01T00:00:00-0500. Defaults to current time. + short-summary: ARM ID of a resource. + - name: --namespace + short-summary: Resource provider namespace. - name: --caller - short-summary: Caller to look for when querying. + short-summary: Caller to query for, such as an e-mail address or service principal ID. - name: --status short-summary: > - Status value to query (ex: Failed) + Status to query for (ex: Failed) - name: --max-events - short-summary: Maximum number of records to be returned by the command. + short-summary: Maximum number of records to return. - name: --select - short-summary: Space-separated list of event names to select. + short-summary: Space-separated list of properties to return. + - name: --offset + short-summary: > + Time offset of the query range, in ##d##h format. + long-summary: > + Can be used with either --start-time or --end-time. If used with --start-time, then + the end time will be calculated by adding the offset. If used with --end-time (default), then + the start time will be calculated by subtracting the offset. If --start-time and --end-time are + provided, then --offset will be ignored. + examples: + - name: List all events from July 1st, looking forward one week. + text: az monitor activity-log list --start-date 2018-07-01 --offset 7d + - name: List events within the past six hours based on a correlation ID. + text: az monitor activity-log list --correlation-id b5eac9d2-e829-4c9a-9efb-586d19417c5f + - name: List events within the past hour based on resource group. + text: az monitor activity-log list -g {ResourceGroup} --offset 1h """ helps['monitor activity-log list-categories'] = """ diff --git a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/_params.py b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/_params.py index 5509f051e64..7687bb17df1 100644 --- a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/_params.py +++ b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/_params.py @@ -8,22 +8,22 @@ from azure.cli.core.util import get_json_object from azure.cli.core.commands.parameters import ( - get_location_type, tags_type, get_three_state_flag, get_enum_type, get_datetime_type) + get_location_type, tags_type, get_three_state_flag, get_enum_type, get_datetime_type, resource_group_name_type) from azure.cli.core.commands.validators import get_default_location_from_resource_group from azure.cli.command_modules.monitor.actions import ( AlertAddAction, AlertRemoveAction, ConditionAction, AutoscaleAddAction, AutoscaleRemoveAction, - AutoscaleScaleAction, AutoscaleConditionAction, period_type, + AutoscaleScaleAction, AutoscaleConditionAction, get_period_type, timezone_offset_type, timezone_name_type, MetricAlertConditionAction, MetricAlertAddAction) from azure.cli.command_modules.monitor.util import get_operator_map, get_aggregation_map from azure.cli.command_modules.monitor.validators import ( process_webhook_prop, validate_autoscale_recurrence, validate_autoscale_timegrain, get_action_group_validator, - get_action_group_id_validator) + get_action_group_id_validator, validate_metric_dimension) # pylint: disable=line-too-long, too-many-statements def load_arguments(self, _): - from azure.mgmt.monitor.models import ConditionOperator, TimeAggregationOperator + from azure.mgmt.monitor.models import ConditionOperator, TimeAggregationOperator, EventData name_arg_type = CLIArgumentType(options_list=['--name', '-n'], metavar='NAME') webhook_prop_type = CLIArgumentType(validator=process_webhook_prop, nargs='*') @@ -73,7 +73,7 @@ def load_arguments(self, _): c.argument('operator', arg_type=get_enum_type(get_operator_map().keys())) c.argument('threshold') c.argument('aggregation', arg_type=get_enum_type(get_aggregation_map().keys())) - c.argument('period', type=period_type) + c.argument('period', type=get_period_type()) for scope in ['monitor alert show-incident', 'monitor alert list-incidents']: with self.argument_context(scope) as c: @@ -92,26 +92,30 @@ def load_arguments(self, _): c.resource_parameter('resource_uri', arg_group='Target Resource') with self.argument_context('monitor metrics list') as c: - from .validators import (process_metric_timespan, process_metric_aggregation, process_metric_result_type, - process_metric_dimension, validate_metric_names) from azure.mgmt.monitor.models import AggregationType - c.resource_parameter('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', arg_type=get_enum_type(t for t in AggregationType if t.name != 'none'), nargs='*', validator=process_metric_aggregation) - c.argument('metricnames', options_list=['--metrics'], nargs='+', help='Space-separated list of metric names to retrieve.', validator=validate_metric_names) - c.ignore('timespan', 'result_type') + c.resource_parameter('resource', arg_group='Target Resource') + c.argument('metadata', action='store_true') + c.argument('dimension', nargs='*', validator=validate_metric_dimension) + c.argument('aggregation', arg_type=get_enum_type(t for t in AggregationType if t.name != 'none'), nargs='*') + c.argument('metrics', nargs='+', help='Space-separated list of metric names to retrieve.') + c.argument('orderby', help='Aggregation to use for sorting results and the direction of the sort. Only one order can be specificed. Examples: sum asc') + c.argument('top', help='Max number of records to retrieve. Valid only if --filter used.') + c.argument('filters', options_list='--filter') + c.argument('metric_namespace', options_list='--namespace') + + with self.argument_context('monitor metrics list', arg_group='Time') as c: + c.argument('start_time', arg_type=get_datetime_type(help='Start time of the query.')) + c.argument('end_time', arg_type=get_datetime_type(help='End time of the query. Defaults to the current time.')) + c.argument('offset', type=get_period_type(as_timedelta=True)) + c.argument('interval', arg_group='Time', type=get_period_type()) # endregion # region MetricAlerts with self.argument_context('monitor metrics alert') as c: c.argument('rule_name', name_arg_type, id_part='name', help='Name of the alert rule.') c.argument('severity', type=int, help='Severity of the alert from 0 (low) to 4 (high).') - c.argument('window_size', type=period_type, help='Time over which to aggregate metrics in "##h##m##s" format.') - c.argument('evaluation_frequency', type=period_type, help='Frequency with which to evaluate the rule in "##h##m##s" format.') + c.argument('window_size', type=get_period_type(), help='Time over which to aggregate metrics in "##h##m##s" format.') + c.argument('evaluation_frequency', type=get_period_type(), help='Frequency with which to evaluate the rule in "##h##m##s" format.') c.argument('auto_mitigate', arg_type=get_three_state_flag(), help='Automatically resolve the alert.') c.argument('condition', options_list=['--condition'], action=MetricAlertConditionAction, nargs='+') c.argument('description', help='Free-text description of the rule.') @@ -249,17 +253,23 @@ def load_arguments(self, _): # region ActivityLog with self.argument_context('monitor activity-log list') as c: - c.argument('select', nargs='+') + activity_log_props = [x['key'] for x in EventData()._attribute_map.values()] # pylint: disable=protected-access + c.argument('select', nargs='+', arg_type=get_enum_type(activity_log_props)) + c.argument('max_events', type=int) + + with self.argument_context('monitor activity-log list', arg_group='Time') as c: + c.argument('start_time', arg_type=get_datetime_type(help='Start time of the query.')) + c.argument('end_time', arg_type=get_datetime_type(help='End time of the query. Defaults to the current time.')) + c.argument('offset', type=get_period_type(as_timedelta=True)) - with self.argument_context('monitor activity-log list', arg_group='OData Filter') as c: + with self.argument_context('monitor activity-log list', arg_group='Filter') as c: + c.argument('filters', deprecate_info=c.deprecate(target='--filters', hide=True, expiration='2.1.0'), help='OData filters. Will ignore other filter arguments.') c.argument('correlation_id') - c.argument('caller') - c.argument('resource_group') + c.argument('resource_group', resource_group_name_type) c.argument('resource_id') - c.argument('resource_provider') + c.argument('resource_provider', options_list=['--namespace', c.deprecate(target='--resource-provider', redirect='--namespace', hide=True, expiration='2.1.0')]) + c.argument('caller') c.argument('status') - c.argument('start_time') - c.argument('end_time') # endregion # region ActionGroup diff --git a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/actions.py b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/actions.py index 8149258c7c5..3db63944204 100644 --- a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/actions.py +++ b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/actions.py @@ -49,31 +49,44 @@ def timezone_offset_type(value): return value -def period_type(value): - - import re - - def _get_substring(indices): - if indices == tuple([-1, -1]): - return '' - return value[indices[0]: indices[1]] - - regex = r'(p)?(\d+y)?(\d+m)?(\d+d)?(t)?(\d+h)?(\d+m)?(\d+s)?' - match = re.match(regex, value.lower()) - match_len = match.regs[0] - if match_len != tuple([0, len(value)]): - raise ValueError - # simply return value if a valid ISO8601 string is supplied - if match.regs[1] != tuple([-1, -1]) and match.regs[5] != tuple([-1, -1]): - return value - - # if shorthand is used, only support days, minutes, hours, seconds - # ensure M is interpretted as minutes - days = _get_substring(match.regs[4]) - minutes = _get_substring(match.regs[6]) or _get_substring(match.regs[3]) - hours = _get_substring(match.regs[7]) - seconds = _get_substring(match.regs[8]) - return 'P{}T{}{}{}'.format(days, minutes, hours, seconds).upper() +def get_period_type(as_timedelta=False): + + def period_type(value): + + import re + + def _get_substring(indices): + if indices == tuple([-1, -1]): + return '' + return value[indices[0]: indices[1]] + + regex = r'(p)?(\d+y)?(\d+m)?(\d+d)?(t)?(\d+h)?(\d+m)?(\d+s)?' + match = re.match(regex, value.lower()) + match_len = match.span(0) + if match_len != tuple([0, len(value)]): + raise ValueError + # simply return value if a valid ISO8601 string is supplied + if match.span(1) != tuple([-1, -1]) and match.span(5) != tuple([-1, -1]): + return value + + # if shorthand is used, only support days, minutes, hours, seconds + # ensure M is interpretted as minutes + days = _get_substring(match.span(4)) + hours = _get_substring(match.span(6)) + minutes = _get_substring(match.span(7)) or _get_substring(match.span(3)) + seconds = _get_substring(match.span(8)) + + if as_timedelta: + from datetime import timedelta + return timedelta( + days=int(days[:-1]) if days else 0, + hours=int(hours[:-1]) if hours else 0, + minutes=int(minutes[:-1]) if minutes else 0, + seconds=int(seconds[:-1]) if seconds else 0 + ) + return 'P{}T{}{}{}'.format(days, minutes, hours, seconds).upper() + + return period_type # pylint: disable=protected-access, too-few-public-methods @@ -129,7 +142,7 @@ def __call__(self, parser, namespace, values, option_string=None): operator = get_operator_map()[values[-4]] threshold = int(values[-3]) aggregation = get_aggregation_map()[values[-2].lower()] - window = period_type(values[-1]) + window = get_period_type()(values[-1]) metric = RuleMetricDataSource(resource_uri=None, metric_name=metric_name) # target URI will be filled in later condition = ThresholdRuleCondition( operator=operator, threshold=threshold, data_source=metric, @@ -228,7 +241,7 @@ def __call__(self, parser, namespace, values, option_string=None): operator = get_autoscale_operator_map()[values[-4]] threshold = int(values[-3]) aggregation = get_autoscale_aggregation_map()[values[-2].lower()] - window = period_type(values[-1]) + window = get_period_type()(values[-1]) except (IndexError, KeyError): from knack.util import CLIError raise CLIError('usage error: --condition METRIC {==,!=,>,>=,<,<=} ' diff --git a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/commands.py b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/commands.py index b28cae5b258..a7e3cc2fda8 100644 --- a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/commands.py +++ b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/commands.py @@ -10,13 +10,17 @@ def load_command_table(self, _): from ._client_factory import ( - cf_alert_rules, cf_metrics, cf_metric_def, cf_alert_rule_incidents, cf_log_profiles, cf_autoscale, + cf_alert_rules, 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, cf_metric_alerts) from ._exception_handler import monitor_exception_handler, missing_resource_handler from .transformers import (action_group_list_table) from .validators import process_autoscale_create_namespace + monitor_custom = CliCommandType( + operations_tmpl='azure.cli.command_modules.monitor.custom#{}', + exception_handler=monitor_exception_handler) + action_group_sdk = CliCommandType( operations_tmpl='azure.mgmt.monitor.operations.action_groups_operations#ActionGroupsOperations.{}', client_factory=cf_action_groups, @@ -27,9 +31,9 @@ def load_command_table(self, _): client_factory=cf_action_groups, exception_handler=monitor_exception_handler) - activity_log_custom = CliCommandType( - operations_tmpl='azure.cli.command_modules.monitor.operations.activity_log#{}', - client_factory=cf_activity_log, + activity_log_sdk = CliCommandType( + operations_tmpl='azure.mgmt.monitor.operations.event_categories_operations#EventCategoriesOperations.{}', + client_factory=cf_event_categories, exception_handler=monitor_exception_handler) activity_log_alerts_sdk = CliCommandType( @@ -87,11 +91,6 @@ def load_command_table(self, _): client_factory=cf_log_profiles, exception_handler=monitor_exception_handler) - metric_operations_sdk = CliCommandType( - operations_tmpl='azure.mgmt.monitor.operations.metrics_operations#MetricsOperations.{}', - client_factory=cf_metrics, - exception_handler=monitor_exception_handler) - alert_custom = CliCommandType( operations_tmpl='azure.cli.command_modules.monitor.operations.metric_alert#{}', client_factory=cf_alert_rules, @@ -116,9 +115,9 @@ def load_command_table(self, _): g.generic_update_command('update', custom_func_name='update_action_groups', setter_arg_name='action_group', table_transformer=action_group_list_table) - with self.command_group('monitor activity-log', activity_log_custom) as g: - g.command('list', 'list_activity_log') - g.command('list-categories', 'list', operations_tmpl='azure.mgmt.monitor.operations.event_categories_operations#EventCategoriesOperations.{}', client_factory=cf_event_categories) + with self.command_group('monitor activity-log', activity_log_sdk) as g: + g.custom_command('list', 'list_activity_log', client_factory=cf_activity_log) + g.command('list-categories', 'list') with self.command_group('monitor activity-log alert', activity_log_alerts_sdk, custom_command_type=activity_log_alerts_custom) as g: g.custom_command('list', 'list_activity_logs_alert') @@ -191,7 +190,7 @@ def load_command_table(self, _): with self.command_group('monitor metrics') as g: from .transformers import metrics_table, metrics_definitions_table - g.command('list', 'list', command_type=metric_operations_sdk, table_transformer=metrics_table) + g.command('list', 'list_metrics', command_type=monitor_custom, table_transformer=metrics_table) g.command('list-definitions', 'list', command_type=metric_definitions_sdk, table_transformer=metrics_definitions_table) with self.command_group('monitor metrics alert', metric_alert_sdk, custom_command_type=alert_custom, client_factory=cf_metric_alerts) as g: diff --git a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/operations/activity_log.py b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/custom.py similarity index 53% rename from src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/operations/activity_log.py rename to src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/custom.py index 486aa243ee0..4982ab2fb38 100644 --- a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/operations/activity_log.py +++ b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/custom.py @@ -3,48 +3,46 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- -from azure.cli.command_modules.monitor.util import validate_time_range_and_add_defaults +from knack.log import get_logger +from azure.cli.command_modules.monitor._client_factory import cf_metrics +logger = get_logger(__name__) + + +# region ActivityLog 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): + select=None, offset='6h'): if filters: odata_filters = filters else: - from knack.util import CLIError - 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) + start_time, end_time, caller, status, offset) select_filters = _activity_log_select_filter_builder(select) + logger.info('OData Filter: %s', odata_filters) + logger.info('Select Filter: %s', select_filters) 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) + start_time=None, end_time=None, caller=None, status=None, offset=None): + from datetime import datetime + import dateutil.parser + + if not start_time and not end_time: + # if neither value provided, end_time is now + end_time = datetime.utcnow().isoformat() + if not start_time: + # if no start_time, apply offset backwards from end_time + start_time = (dateutil.parser.parse(end_time) - offset).isoformat() + elif not end_time: + # if no end_time, apply offset fowards from start_time + end_time = (dateutil.parser.parse(start_time) + offset).isoformat() + + odata_filters = 'eventTimestamp ge {} and eventTimestamp le {}'.format(start_time, end_time) if correlation_id: odata_filters = _build_odata_filter(odata_filters, 'correlation_id', correlation_id, 'correlationId') @@ -96,3 +94,43 @@ def _limit_results(paged, limit): else: break return list(results) +# endregion + + +# region Metrics +# pylint:disable=unused-argument +def list_metrics(cmd, resource, + start_time=None, end_time=None, offset='1h', interval='1m', + metadata=None, dimension=None, aggregation=None, metrics=None, + filters=None, metric_namespace=None, orderby=None, top=10): + + from azure.mgmt.monitor.models import ResultType + from datetime import datetime + import dateutil.parser + from six.moves.urllib.parse import quote_plus + + if not start_time and not end_time: + # if neither value provided, end_time is now + end_time = datetime.utcnow().isoformat() + if not start_time: + # if no start_time, apply offset backwards from end_time + start_time = (dateutil.parser.parse(end_time) - offset).isoformat() + elif not end_time: + # if no end_time, apply offset fowards from start_time + end_time = (dateutil.parser.parse(start_time) + offset).isoformat() + + timespan = '{}/{}'.format(start_time, end_time) + + client = cf_metrics(cmd.cli_ctx, None) + return client.list( + resource_uri=resource, + timespan=quote_plus(timespan), + interval=interval, + metricnames=','.join(metrics) if metrics else None, + aggregation=','.join(aggregation) if aggregation else None, + top=top, + orderby=orderby, + filter=filters, + result_type=ResultType.metadata if metadata else None, + metricnamespace=metric_namespace) +# endregion diff --git a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/operations/diagnostics_settings.py b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/operations/diagnostics_settings.py index f6f73b59c8f..9b6ba1ef53d 100644 --- a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/operations/diagnostics_settings.py +++ b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/operations/diagnostics_settings.py @@ -13,7 +13,6 @@ def create_diagnostics_settings(client, name, resource_uri, storage_account=None, workspace=None): from azure.mgmt.monitor.models import DiagnosticSettingsResource - parameters = DiagnosticSettingsResource(storage_account_id=storage_account, workspace_id=workspace, event_hub_name=event_hub, diff --git a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/recordings/test_activity_log_list_scenario.yaml b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/recordings/test_activity_log_list_scenario.yaml new file mode 100644 index 00000000000..8d65a6b52bd --- /dev/null +++ b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/recordings/test_activity_log_list_scenario.yaml @@ -0,0 +1,201 @@ +interactions: +- request: + body: '{"location": "southcentralus", "tags": {"product": "azurecli", "cause": + "automation", "date": "2018-10-18T15:40:18Z"}}' + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [group create] + Connection: [keep-alive] + Content-Length: ['118'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.6.1 (Windows-10-10.0.17763-SP0) msrest/0.6.1 msrest_azure/0.4.34 + resourcemanagementclient/2.0.0 Azure-SDK-For-Python AZURECLI/2.0.49] + accept-language: [en-US] + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001?api-version=2018-05-01 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001","name":"clitest.rg000001","location":"southcentralus","tags":{"product":"azurecli","cause":"automation","date":"2018-10-18T15:40:18Z"},"properties":{"provisioningState":"Succeeded"}}'} + headers: + cache-control: [no-cache] + content-length: ['392'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 18 Oct 2018 15:40:21 GMT'] + expires: ['-1'] + pragma: [no-cache] + strict-transport-security: [max-age=31536000; includeSubDomains] + x-content-type-options: [nosniff] + 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.1 (Windows-10-10.0.17763-SP0) msrest/0.6.1 msrest_azure/0.4.34 + azure-mgmt-storage/2.0.0rc4 Azure-SDK-For-Python AZURECLI/2.0.49] + 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=2018-03-01-preview + response: + body: {string: ''} + headers: + cache-control: [no-cache] + content-length: ['0'] + content-type: [text/plain; charset=utf-8] + date: ['Thu, 18 Oct 2018 15:40:24 GMT'] + expires: ['-1'] + location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Storage/locations/westus/asyncoperations/ffb03813-dff1-4b50-950a-b540fcb4db7d?monitor=true&api-version=2018-03-01-preview'] + pragma: [no-cache] + server: ['Microsoft-Azure-Storage-Resource-Provider/1.0,Microsoft-HTTPAPI/2.0 + Microsoft-HTTPAPI/2.0'] + strict-transport-security: [max-age=31536000; includeSubDomains] + x-content-type-options: [nosniff] + 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] + User-Agent: [python/3.6.1 (Windows-10-10.0.17763-SP0) msrest/0.6.1 msrest_azure/0.4.34 + azure-mgmt-storage/2.0.0rc4 Azure-SDK-For-Python AZURECLI/2.0.49] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Storage/locations/westus/asyncoperations/ffb03813-dff1-4b50-950a-b540fcb4db7d?monitor=true&api-version=2018-03-01-preview + response: + body: {string: ''} + headers: + cache-control: [no-cache] + content-length: ['0'] + content-type: [text/plain; charset=utf-8] + date: ['Thu, 18 Oct 2018 15:40:41 GMT'] + expires: ['-1'] + location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Storage/locations/westus/asyncoperations/ffb03813-dff1-4b50-950a-b540fcb4db7d?monitor=true&api-version=2018-03-01-preview'] + pragma: [no-cache] + server: ['Microsoft-Azure-Storage-Resource-Provider/1.0,Microsoft-HTTPAPI/2.0 + Microsoft-HTTPAPI/2.0'] + strict-transport-security: [max-age=31536000; includeSubDomains] + x-content-type-options: [nosniff] + status: {code: 202, message: Accepted} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [storage account create] + Connection: [keep-alive] + User-Agent: [python/3.6.1 (Windows-10-10.0.17763-SP0) msrest/0.6.1 msrest_azure/0.4.34 + azure-mgmt-storage/2.0.0rc4 Azure-SDK-For-Python AZURECLI/2.0.49] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Storage/locations/westus/asyncoperations/ffb03813-dff1-4b50-950a-b540fcb4db7d?monitor=true&api-version=2018-03-01-preview + response: + body: {string: '{"sku":{"name":"Standard_LRS","tier":"Standard"},"kind":"Storage","id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002","name":"clitest000002","type":"Microsoft.Storage/storageAccounts","location":"westus","tags":{},"properties":{"networkAcls":{"bypass":"AzureServices","virtualNetworkRules":[],"ipRules":[],"defaultAction":"Allow"},"supportsHttpsTrafficOnly":false,"encryption":{"services":{"file":{"enabled":true,"lastEnabledTime":"2018-10-18T15:40:24.2532206Z"},"blob":{"enabled":true,"lastEnabledTime":"2018-10-18T15:40:24.2532206Z"}},"keySource":"Microsoft.Storage"},"provisioningState":"Succeeded","creationTime":"2018-10-18T15:40:24.1750746Z","primaryEndpoints":{"blob":"https://clitest000002.blob.core.windows.net/","queue":"https://clitest000002.queue.core.windows.net/","table":"https://clitest000002.table.core.windows.net/","file":"https://clitest000002.file.core.windows.net/"},"primaryLocation":"westus","statusOfPrimary":"available"}}'} + headers: + cache-control: [no-cache] + content-length: ['1169'] + content-type: [application/json] + date: ['Thu, 18 Oct 2018 15:40:44 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: ['Microsoft-Azure-Storage-Resource-Provider/1.0,Microsoft-HTTPAPI/2.0 + Microsoft-HTTPAPI/2.0'] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-content-type-options: [nosniff] + 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.1 (Windows-10-10.0.17763-SP0) msrest/0.6.1 msrest_azure/0.4.34 + azure-mgmt-storage/2.0.0rc4 Azure-SDK-For-Python AZURECLI/2.0.49] + 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=2018-03-01-preview + response: + body: {string: '{"keys": [{"keyName": "key1", "value": "veryFakedStorageAccountKey==", + "permissions": "FULL"}, {"keyName": "key2", "value": "veryFakedStorageAccountKey==", + "permissions": "FULL"}]}'} + headers: + cache-control: [no-cache] + content-length: ['288'] + content-type: [application/json] + date: ['Thu, 18 Oct 2018 15:40:45 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: ['Microsoft-Azure-Storage-Resource-Provider/1.0,Microsoft-HTTPAPI/2.0 + Microsoft-HTTPAPI/2.0'] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-content-type-options: [nosniff] + x-ms-ratelimit-remaining-subscription-writes: ['1198'] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [monitor activity-log list] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.6.1 (Windows-10-10.0.17763-SP0) msrest/0.6.1 msrest_azure/0.4.34 + azure-mgmt-monitor/0.5.2 Azure-SDK-For-Python AZURECLI/2.0.49] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/microsoft.insights/eventtypes/management/values?api-version=2015-04-01&$filter=eventTimestamp%20ge%202018-01-01T00%3A00%3A00%2B00%3A00%20and%20eventTimestamp%20le%202999-01-01T00%3A00%3A00%2B00%3A00 + response: + body: {string: '{"Code":"BadRequest","Message":"The start time cannot be more + than 90 days in the past."}'} + headers: + cache-control: [no-cache] + content-length: ['89'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 18 Oct 2018 15:40:46 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-IIS/8.5] + strict-transport-security: [max-age=31536000; includeSubDomains] + x-content-type-options: [nosniff] + status: {code: 400, message: Bad Request} +- 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.1 (Windows-10-10.0.17763-SP0) msrest/0.6.1 msrest_azure/0.4.34 + resourcemanagementclient/2.0.0 Azure-SDK-For-Python AZURECLI/2.0.49] + accept-language: [en-US] + method: DELETE + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001?api-version=2018-05-01 + response: + body: {string: ''} + headers: + cache-control: [no-cache] + content-length: ['0'] + date: ['Thu, 18 Oct 2018 15:40:48 GMT'] + expires: ['-1'] + location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/operationresults/eyJqb2JJZCI6IlJFU09VUkNFR1JPVVBERUxFVElPTkpPQi1DTElURVNUOjJFUkdJM1lHSTQ0WkdYRktCQllTNFZEUEpLN1Y3VDNFNEVUMktLUHxFQURFRkQ2REU4MzFGRUJFLVNPVVRIQ0VOVFJBTFVTIiwiam9iTG9jYXRpb24iOiJzb3V0aGNlbnRyYWx1cyJ9?api-version=2018-05-01'] + pragma: [no-cache] + strict-transport-security: [max-age=31536000; includeSubDomains] + x-content-type-options: [nosniff] + x-ms-ratelimit-remaining-subscription-deletes: ['14999'] + status: {code: 202, message: Accepted} +version: 1 diff --git a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/recordings/test_monitor_metrics_scenario.yaml b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/recordings/test_monitor_metrics_scenario.yaml index d524620251b..a3560b96a90 100644 --- a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/recordings/test_monitor_metrics_scenario.yaml +++ b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/recordings/test_monitor_metrics_scenario.yaml @@ -1,26 +1,26 @@ interactions: - request: - body: '{"location": "southcentralus", "tags": {"use": "az-test"}}' + body: '{"location": "southcentralus", "tags": {"product": "azurecli", "cause": + "automation", "date": "2018-10-18T15:42:17Z"}}' headers: Accept: [application/json] Accept-Encoding: ['gzip, deflate'] CommandName: [group create] Connection: [keep-alive] - Content-Length: ['58'] + Content-Length: ['118'] Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.6.1 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.27 - msrest_azure/0.4.22 resourcemanagementclient/1.2.1 Azure-SDK-For-Python - AZURECLI/2.0.30] + User-Agent: [python/3.6.1 (Windows-10-10.0.17763-SP0) msrest/0.6.1 msrest_azure/0.4.34 + resourcemanagementclient/2.0.0 Azure-SDK-For-Python AZURECLI/2.0.49] accept-language: [en-US] method: PUT uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001?api-version=2018-05-01 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"}}'} + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001","name":"clitest.rg000001","location":"southcentralus","tags":{"product":"azurecli","cause":"automation","date":"2018-10-18T15:42:17Z"},"properties":{"provisioningState":"Succeeded"}}'} headers: cache-control: [no-cache] - content-length: ['336'] + content-length: ['392'] content-type: [application/json; charset=utf-8] - date: ['Thu, 15 Mar 2018 16:42:39 GMT'] + date: ['Thu, 18 Oct 2018 15:42:20 GMT'] expires: ['-1'] pragma: [no-cache] strict-transport-security: [max-age=31536000; includeSubDomains] @@ -37,8 +37,8 @@ interactions: Connection: [keep-alive] Content-Length: ['125'] Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.6.1 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.27 - msrest_azure/0.4.22 azure-mgmt-storage/1.5.0 Azure-SDK-For-Python AZURECLI/2.0.30] + User-Agent: [python/3.6.1 (Windows-10-10.0.17763-SP0) msrest/0.6.1 msrest_azure/0.4.34 + azure-mgmt-storage/2.0.0rc4 Azure-SDK-For-Python AZURECLI/2.0.49] 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=2018-03-01-preview @@ -48,15 +48,15 @@ interactions: cache-control: [no-cache] content-length: ['0'] content-type: [text/plain; charset=utf-8] - date: ['Thu, 15 Mar 2018 16:42:41 GMT'] + date: ['Thu, 18 Oct 2018 15:42:22 GMT'] expires: ['-1'] - location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Storage/locations/westus/asyncoperations/dd80b296-ec79-4a83-b078-bf81bba37303?monitor=true&api-version=2017-10-01'] + location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Storage/locations/westus/asyncoperations/5f53215c-e1d4-454c-ac0e-ef05d61bf6f2?monitor=true&api-version=2018-03-01-preview'] pragma: [no-cache] server: ['Microsoft-Azure-Storage-Resource-Provider/1.0,Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0'] strict-transport-security: [max-age=31536000; includeSubDomains] x-content-type-options: [nosniff] - x-ms-ratelimit-remaining-subscription-writes: ['1199'] + x-ms-ratelimit-remaining-subscription-writes: ['1198'] status: {code: 202, message: Accepted} - request: body: null @@ -65,19 +65,43 @@ interactions: Accept-Encoding: ['gzip, deflate'] CommandName: [storage account create] Connection: [keep-alive] - Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.6.1 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.27 - msrest_azure/0.4.22 azure-mgmt-storage/1.5.0 Azure-SDK-For-Python AZURECLI/2.0.30] - accept-language: [en-US] + User-Agent: [python/3.6.1 (Windows-10-10.0.17763-SP0) msrest/0.6.1 msrest_azure/0.4.34 + azure-mgmt-storage/2.0.0rc4 Azure-SDK-For-Python AZURECLI/2.0.49] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Storage/locations/westus/asyncoperations/5f53215c-e1d4-454c-ac0e-ef05d61bf6f2?monitor=true&api-version=2018-03-01-preview + response: + body: {string: ''} + headers: + cache-control: [no-cache] + content-length: ['0'] + content-type: [text/plain; charset=utf-8] + date: ['Thu, 18 Oct 2018 15:42:39 GMT'] + expires: ['-1'] + location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Storage/locations/westus/asyncoperations/5f53215c-e1d4-454c-ac0e-ef05d61bf6f2?monitor=true&api-version=2018-03-01-preview'] + pragma: [no-cache] + server: ['Microsoft-Azure-Storage-Resource-Provider/1.0,Microsoft-HTTPAPI/2.0 + Microsoft-HTTPAPI/2.0'] + strict-transport-security: [max-age=31536000; includeSubDomains] + x-content-type-options: [nosniff] + status: {code: 202, message: Accepted} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [storage account create] + Connection: [keep-alive] + User-Agent: [python/3.6.1 (Windows-10-10.0.17763-SP0) msrest/0.6.1 msrest_azure/0.4.34 + azure-mgmt-storage/2.0.0rc4 Azure-SDK-For-Python AZURECLI/2.0.49] method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Storage/locations/westus/asyncoperations/dd80b296-ec79-4a83-b078-bf81bba37303?monitor=true&api-version=2017-10-01 + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Storage/locations/westus/asyncoperations/5f53215c-e1d4-454c-ac0e-ef05d61bf6f2?monitor=true&api-version=2018-03-01-preview response: - body: {string: '{"sku":{"name":"Standard_LRS","tier":"Standard"},"kind":"Storage","id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002","name":"clitest000002","type":"Microsoft.Storage/storageAccounts","location":"westus","tags":{},"properties":{"networkAcls":{"bypass":"AzureServices","virtualNetworkRules":[],"ipRules":[],"defaultAction":"Allow"},"trustedDirectories":["54826b22-38d6-4fb2-bad9-b7b93a3e9c5a"],"supportsHttpsTrafficOnly":false,"encryption":{"services":{"file":{"enabled":true,"lastEnabledTime":"2018-03-15T16:42:42.1470827Z"},"blob":{"enabled":true,"lastEnabledTime":"2018-03-15T16:42:42.1470827Z"}},"keySource":"Microsoft.Storage"},"provisioningState":"Succeeded","creationTime":"2018-03-15T16:42:42.0689571Z","primaryEndpoints":{"blob":"https://clitest000002.blob.core.windows.net/","queue":"https://clitest000002.queue.core.windows.net/","table":"https://clitest000002.table.core.windows.net/","file":"https://clitest000002.file.core.windows.net/"},"primaryLocation":"westus","statusOfPrimary":"available"}}'} + body: {string: '{"sku":{"name":"Standard_LRS","tier":"Standard"},"kind":"Storage","id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002","name":"clitest000002","type":"Microsoft.Storage/storageAccounts","location":"westus","tags":{},"properties":{"networkAcls":{"bypass":"AzureServices","virtualNetworkRules":[],"ipRules":[],"defaultAction":"Allow"},"supportsHttpsTrafficOnly":false,"encryption":{"services":{"file":{"enabled":true,"lastEnabledTime":"2018-10-18T15:42:22.6765282Z"},"blob":{"enabled":true,"lastEnabledTime":"2018-10-18T15:42:22.6765282Z"}},"keySource":"Microsoft.Storage"},"provisioningState":"Succeeded","creationTime":"2018-10-18T15:42:22.5830090Z","primaryEndpoints":{"blob":"https://clitest000002.blob.core.windows.net/","queue":"https://clitest000002.queue.core.windows.net/","table":"https://clitest000002.table.core.windows.net/","file":"https://clitest000002.file.core.windows.net/"},"primaryLocation":"westus","statusOfPrimary":"available"}}'} headers: cache-control: [no-cache] - content-length: ['1231'] + content-length: ['1169'] content-type: [application/json] - date: ['Thu, 15 Mar 2018 16:42:59 GMT'] + date: ['Thu, 18 Oct 2018 15:42:42 GMT'] expires: ['-1'] pragma: [no-cache] server: ['Microsoft-Azure-Storage-Resource-Provider/1.0,Microsoft-HTTPAPI/2.0 @@ -96,18 +120,20 @@ interactions: Connection: [keep-alive] Content-Length: ['0'] Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.6.1 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.27 - msrest_azure/0.4.22 azure-mgmt-storage/1.5.0 Azure-SDK-For-Python AZURECLI/2.0.30] + User-Agent: [python/3.6.1 (Windows-10-10.0.17763-SP0) msrest/0.6.1 msrest_azure/0.4.34 + azure-mgmt-storage/2.0.0rc4 Azure-SDK-For-Python AZURECLI/2.0.49] 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=2018-03-01-preview response: - body: {string: '{"keys":[{"keyName":"key1","value":"pPlExOgGyyy+tjvI+cyR4QYH3I6CkOKpYdQtqgTS7O72G94s4LGlErxbe73nfsRsey8Qa5ym23pjiEYlbLBRZw==","permissions":"FULL"},{"keyName":"key2","value":"xXNTAuUmCzWoVGtRMWKZ+WDI+9VSvaZ/QmkFer2ksFzasDxYX73ET8GoUbxjYLEeAFZct9G/P/QhuWzjn4MYYg==","permissions":"FULL"}]}'} + body: {string: '{"keys": [{"keyName": "key1", "value": "veryFakedStorageAccountKey==", + "permissions": "FULL"}, {"keyName": "key2", "value": "veryFakedStorageAccountKey==", + "permissions": "FULL"}]}'} headers: cache-control: [no-cache] content-length: ['288'] content-type: [application/json] - date: ['Thu, 15 Mar 2018 16:43:00 GMT'] + date: ['Thu, 18 Oct 2018 15:42:44 GMT'] expires: ['-1'] pragma: [no-cache] server: ['Microsoft-Azure-Storage-Resource-Provider/1.0,Microsoft-HTTPAPI/2.0 @@ -126,18 +152,18 @@ interactions: CommandName: [storage account show] Connection: [keep-alive] Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.6.1 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.27 - msrest_azure/0.4.22 azure-mgmt-storage/1.5.0 Azure-SDK-For-Python AZURECLI/2.0.30] + User-Agent: [python/3.6.1 (Windows-10-10.0.17763-SP0) msrest/0.6.1 msrest_azure/0.4.34 + azure-mgmt-storage/2.0.0rc4 Azure-SDK-For-Python AZURECLI/2.0.49] 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=2018-03-01-preview response: - body: {string: '{"sku":{"name":"Standard_LRS","tier":"Standard"},"kind":"Storage","id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002","name":"clitest000002","type":"Microsoft.Storage/storageAccounts","location":"westus","tags":{},"properties":{"networkAcls":{"bypass":"AzureServices","virtualNetworkRules":[],"ipRules":[],"defaultAction":"Allow"},"trustedDirectories":["54826b22-38d6-4fb2-bad9-b7b93a3e9c5a"],"supportsHttpsTrafficOnly":false,"encryption":{"services":{"file":{"enabled":true,"lastEnabledTime":"2018-03-15T16:42:42.1470827Z"},"blob":{"enabled":true,"lastEnabledTime":"2018-03-15T16:42:42.1470827Z"}},"keySource":"Microsoft.Storage"},"provisioningState":"Succeeded","creationTime":"2018-03-15T16:42:42.0689571Z","primaryEndpoints":{"blob":"https://clitest000002.blob.core.windows.net/","queue":"https://clitest000002.queue.core.windows.net/","table":"https://clitest000002.table.core.windows.net/","file":"https://clitest000002.file.core.windows.net/"},"primaryLocation":"westus","statusOfPrimary":"available"}}'} + body: {string: '{"sku":{"name":"Standard_LRS","tier":"Standard"},"kind":"Storage","id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002","name":"clitest000002","type":"Microsoft.Storage/storageAccounts","location":"westus","tags":{},"properties":{"networkAcls":{"bypass":"AzureServices","virtualNetworkRules":[],"ipRules":[],"defaultAction":"Allow"},"supportsHttpsTrafficOnly":false,"encryption":{"services":{"file":{"enabled":true,"lastEnabledTime":"2018-10-18T15:42:22.6765282Z"},"blob":{"enabled":true,"lastEnabledTime":"2018-10-18T15:42:22.6765282Z"}},"keySource":"Microsoft.Storage"},"provisioningState":"Succeeded","creationTime":"2018-10-18T15:42:22.5830090Z","primaryEndpoints":{"blob":"https://clitest000002.blob.core.windows.net/","queue":"https://clitest000002.queue.core.windows.net/","table":"https://clitest000002.table.core.windows.net/","file":"https://clitest000002.file.core.windows.net/"},"primaryLocation":"westus","statusOfPrimary":"available"}}'} headers: cache-control: [no-cache] - content-length: ['1231'] + content-length: ['1169'] content-type: [application/json] - date: ['Thu, 15 Mar 2018 16:43:00 GMT'] + date: ['Thu, 18 Oct 2018 15:42:44 GMT'] expires: ['-1'] pragma: [no-cache] server: ['Microsoft-Azure-Storage-Resource-Provider/1.0,Microsoft-HTTPAPI/2.0 @@ -155,29 +181,29 @@ interactions: CommandName: [monitor metrics list-definitions] Connection: [keep-alive] Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.6.1 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.27 - msrest_azure/0.4.22 azure-mgmt-monitor/0.5.0 Azure-SDK-For-Python AZURECLI/2.0.30] + User-Agent: [python/3.6.1 (Windows-10-10.0.17763-SP0) msrest/0.6.1 msrest_azure/0.4.34 + azure-mgmt-monitor/0.5.2 Azure-SDK-For-Python AZURECLI/2.0.49] 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=2018-01-01&metricnamespace=Microsoft.Storage%2FstorageAccounts 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","namespace":"Microsoft.Storage/storageAccounts","category":"Capacity","name":{"value":"UsedCapacity","localizedValue":"Used - capacity"},"isDimensionRequired":false,"unit":"Bytes","primaryAggregationType":"Average","supportedAggregationTypes":["Total","Average","Minimum","Maximum"],"metricAvailabilities":[{"timeGrain":"PT1H","retention":"P93D"},{"timeGrain":"PT6H","retention":"P93D"},{"timeGrain":"PT12H","retention":"P93D"},{"timeGrain":"P1D","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","namespace":"Microsoft.Storage/storageAccounts","category":"Transaction","name":{"value":"Transactions","localizedValue":"Transactions"},"isDimensionRequired":false,"unit":"Count","primaryAggregationType":"Total","supportedAggregationTypes":["Total"],"metricAvailabilities":[{"timeGrain":"PT1M","retention":"P93D"},{"timeGrain":"PT5M","retention":"P93D"},{"timeGrain":"PT15M","retention":"P93D"},{"timeGrain":"PT30M","retention":"P93D"},{"timeGrain":"PT1H","retention":"P93D"},{"timeGrain":"PT6H","retention":"P93D"},{"timeGrain":"PT12H","retention":"P93D"},{"timeGrain":"P1D","retention":"P93D"}],"dimensions":[{"value":"ResponseType","localizedValue":"Response + capacity"},"isDimensionRequired":false,"unit":"Bytes","primaryAggregationType":"Total","supportedAggregationTypes":["Total"],"metricAvailabilities":[{"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","namespace":"Microsoft.Storage/storageAccounts","category":"Transaction","name":{"value":"Transactions","localizedValue":"Transactions"},"isDimensionRequired":false,"unit":"Count","primaryAggregationType":"Total","supportedAggregationTypes":["Total"],"metricAvailabilities":[{"timeGrain":"PT1M","retention":"P93D"},{"timeGrain":"PT5M","retention":"P93D"},{"timeGrain":"PT15M","retention":"P93D"},{"timeGrain":"PT30M","retention":"P93D"},{"timeGrain":"PT1H","retention":"P93D"},{"timeGrain":"PT6H","retention":"P93D"},{"timeGrain":"PT12H","retention":"P93D"},{"timeGrain":"P1D","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","namespace":"Microsoft.Storage/storageAccounts","category":"Transaction","name":{"value":"Ingress","localizedValue":"Ingress"},"isDimensionRequired":false,"unit":"Bytes","primaryAggregationType":"Total","supportedAggregationTypes":["Total","Average","Minimum","Maximum"],"metricAvailabilities":[{"timeGrain":"PT1M","retention":"P93D"},{"timeGrain":"PT5M","retention":"P93D"},{"timeGrain":"PT15M","retention":"P93D"},{"timeGrain":"PT30M","retention":"P93D"},{"timeGrain":"PT1H","retention":"P93D"},{"timeGrain":"PT6H","retention":"P93D"},{"timeGrain":"PT12H","retention":"P93D"},{"timeGrain":"P1D","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","namespace":"Microsoft.Storage/storageAccounts","category":"Transaction","name":{"value":"Egress","localizedValue":"Egress"},"isDimensionRequired":false,"unit":"Bytes","primaryAggregationType":"Total","supportedAggregationTypes":["Total","Average","Minimum","Maximum"],"metricAvailabilities":[{"timeGrain":"PT1M","retention":"P93D"},{"timeGrain":"PT5M","retention":"P93D"},{"timeGrain":"PT15M","retention":"P93D"},{"timeGrain":"PT30M","retention":"P93D"},{"timeGrain":"PT1H","retention":"P93D"},{"timeGrain":"PT6H","retention":"P93D"},{"timeGrain":"PT12H","retention":"P93D"},{"timeGrain":"P1D","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","namespace":"Microsoft.Storage/storageAccounts","category":"Transaction","name":{"value":"SuccessServerLatency","localizedValue":"Success + name"},{"value":"Authentication","localizedValue":"Authentication"}]},{"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","namespace":"Microsoft.Storage/storageAccounts","category":"Transaction","name":{"value":"Ingress","localizedValue":"Ingress"},"isDimensionRequired":false,"unit":"Bytes","primaryAggregationType":"Total","supportedAggregationTypes":["Total","Average","Minimum","Maximum"],"metricAvailabilities":[{"timeGrain":"PT1M","retention":"P93D"},{"timeGrain":"PT5M","retention":"P93D"},{"timeGrain":"PT15M","retention":"P93D"},{"timeGrain":"PT30M","retention":"P93D"},{"timeGrain":"PT1H","retention":"P93D"},{"timeGrain":"PT6H","retention":"P93D"},{"timeGrain":"PT12H","retention":"P93D"},{"timeGrain":"P1D","retention":"P93D"}],"dimensions":[{"value":"GeoType","localizedValue":"Geo + type"},{"value":"ApiName","localizedValue":"API name"},{"value":"Authentication","localizedValue":"Authentication"}]},{"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","namespace":"Microsoft.Storage/storageAccounts","category":"Transaction","name":{"value":"Egress","localizedValue":"Egress"},"isDimensionRequired":false,"unit":"Bytes","primaryAggregationType":"Total","supportedAggregationTypes":["Total","Average","Minimum","Maximum"],"metricAvailabilities":[{"timeGrain":"PT1M","retention":"P93D"},{"timeGrain":"PT5M","retention":"P93D"},{"timeGrain":"PT15M","retention":"P93D"},{"timeGrain":"PT30M","retention":"P93D"},{"timeGrain":"PT1H","retention":"P93D"},{"timeGrain":"PT6H","retention":"P93D"},{"timeGrain":"PT12H","retention":"P93D"},{"timeGrain":"P1D","retention":"P93D"}],"dimensions":[{"value":"GeoType","localizedValue":"Geo + type"},{"value":"ApiName","localizedValue":"API name"},{"value":"Authentication","localizedValue":"Authentication"}]},{"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","namespace":"Microsoft.Storage/storageAccounts","category":"Transaction","name":{"value":"SuccessServerLatency","localizedValue":"Success Server Latency"},"isDimensionRequired":false,"unit":"MilliSeconds","primaryAggregationType":"Average","supportedAggregationTypes":["Total","Average","Minimum","Maximum"],"metricAvailabilities":[{"timeGrain":"PT1M","retention":"P93D"},{"timeGrain":"PT5M","retention":"P93D"},{"timeGrain":"PT15M","retention":"P93D"},{"timeGrain":"PT30M","retention":"P93D"},{"timeGrain":"PT1H","retention":"P93D"},{"timeGrain":"PT6H","retention":"P93D"},{"timeGrain":"PT12H","retention":"P93D"},{"timeGrain":"P1D","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","namespace":"Microsoft.Storage/storageAccounts","category":"Transaction","name":{"value":"SuccessE2ELatency","localizedValue":"Success + type"},{"value":"ApiName","localizedValue":"API name"},{"value":"Authentication","localizedValue":"Authentication"}]},{"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","namespace":"Microsoft.Storage/storageAccounts","category":"Transaction","name":{"value":"SuccessE2ELatency","localizedValue":"Success E2E Latency"},"isDimensionRequired":false,"unit":"MilliSeconds","primaryAggregationType":"Average","supportedAggregationTypes":["Total","Average","Minimum","Maximum"],"metricAvailabilities":[{"timeGrain":"PT1M","retention":"P93D"},{"timeGrain":"PT5M","retention":"P93D"},{"timeGrain":"PT15M","retention":"P93D"},{"timeGrain":"PT30M","retention":"P93D"},{"timeGrain":"PT1H","retention":"P93D"},{"timeGrain":"PT6H","retention":"P93D"},{"timeGrain":"PT12H","retention":"P93D"},{"timeGrain":"P1D","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","namespace":"Microsoft.Storage/storageAccounts","category":"Transaction","name":{"value":"Availability","localizedValue":"Availability"},"isDimensionRequired":false,"unit":"Percent","primaryAggregationType":"Average","supportedAggregationTypes":["Average","Minimum","Maximum"],"metricAvailabilities":[{"timeGrain":"PT1M","retention":"P93D"},{"timeGrain":"PT5M","retention":"P93D"},{"timeGrain":"PT15M","retention":"P93D"},{"timeGrain":"PT30M","retention":"P93D"},{"timeGrain":"PT1H","retention":"P93D"},{"timeGrain":"PT6H","retention":"P93D"},{"timeGrain":"PT12H","retention":"P93D"},{"timeGrain":"P1D","retention":"P93D"}],"dimensions":[{"value":"GeoType","localizedValue":"Geo - type"},{"value":"ApiName","localizedValue":"API name"}]}]}'} + type"},{"value":"ApiName","localizedValue":"API name"},{"value":"Authentication","localizedValue":"Authentication"}]},{"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","namespace":"Microsoft.Storage/storageAccounts","category":"Transaction","name":{"value":"Availability","localizedValue":"Availability"},"isDimensionRequired":false,"unit":"Percent","primaryAggregationType":"Average","supportedAggregationTypes":["Average","Minimum","Maximum"],"metricAvailabilities":[{"timeGrain":"PT1M","retention":"P93D"},{"timeGrain":"PT5M","retention":"P93D"},{"timeGrain":"PT15M","retention":"P93D"},{"timeGrain":"PT30M","retention":"P93D"},{"timeGrain":"PT1H","retention":"P93D"},{"timeGrain":"PT6H","retention":"P93D"},{"timeGrain":"PT12H","retention":"P93D"},{"timeGrain":"P1D","retention":"P93D"}],"dimensions":[{"value":"GeoType","localizedValue":"Geo + type"},{"value":"ApiName","localizedValue":"API name"},{"value":"Authentication","localizedValue":"Authentication"}]}]}'} headers: - __handlingserverid__: [shoeboxproxyustwo_shoeboxproxyustwo-black_MetricsMP_IN_6] + __handlingserverid__: [shoeboxproxyustwo_shoeboxproxyustwo-black_MetricsMP_IN_0] cache-control: [no-cache] - content-length: ['8519'] + content-length: ['8733'] content-type: [application/json] - date: ['Thu, 15 Mar 2018 16:43:00 GMT'] + date: ['Thu, 18 Oct 2018 15:42:46 GMT'] server: [Microsoft-IIS/8.5] strict-transport-security: [max-age=31536000; includeSubDomains] transfer-encoding: [chunked] @@ -194,19 +220,77 @@ interactions: CommandName: [monitor metrics list] Connection: [keep-alive] Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.6.1 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.27 - msrest_azure/0.4.22 azure-mgmt-monitor/0.5.0 Azure-SDK-For-Python AZURECLI/2.0.30] + User-Agent: [python/3.6.1 (Windows-10-10.0.17763-SP0) msrest/0.6.1 msrest_azure/0.4.34 + azure-mgmt-monitor/0.5.2 Azure-SDK-For-Python AZURECLI/2.0.49] 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/metrics?timespan=2018-01-01T00%3A00%3A00Z%2F2999-01-01T00%3A00%3A00Z&metricnames=Ingress%2CEgress&api-version=2018-01-01&metricnamespace=Microsoft.Storage%2FstorageAccounts + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/providers/microsoft.insights/metrics?timespan=2018-01-01T00%253A00%253A00%252B00%253A00%252F2999-01-01T00%253A00%253A00%252B00%253A00&interval=PT1M&metricnames=Ingress%2CEgress&top=10&api-version=2018-01-01&metricnamespace=Microsoft.Storage%2FstorageAccounts response: body: {string: '{"cost":0,"timespan":"2998-12-01T00:00:00Z/2999-01-01T00:00:00Z","interval":"PT1M","value":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/providers/Microsoft.Insights/metrics/Ingress","type":"Microsoft.Insights/metrics","name":{"value":"Ingress","localizedValue":"Ingress"},"unit":"Bytes","timeseries":[]},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/providers/Microsoft.Insights/metrics/Egress","type":"Microsoft.Insights/metrics","name":{"value":"Egress","localizedValue":"Egress"},"unit":"Bytes","timeseries":[]}],"namespace":"Microsoft.Storage/storageAccounts","resourceregion":"westus"}'} headers: - __handlingserverid__: [shoeboxproxyustwo_shoeboxproxyustwo-red_MetricsMP_IN_6] + __handlingserverid__: [shoeboxproxyustwo_shoeboxproxyustwo-black_MetricsMP_IN_0] + cache-control: [no-cache] + content-length: ['938'] + content-type: [application/json] + date: ['Thu, 18 Oct 2018 15:42:46 GMT'] + server: [Microsoft-IIS/8.5] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: ['Accept-Encoding,Accept-Encoding'] + x-aspnet-version: [4.0.30319] + x-content-type-options: [nosniff] + x-powered-by: [ASP.NET] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [monitor metrics list] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.6.1 (Windows-10-10.0.17763-SP0) msrest/0.6.1 msrest_azure/0.4.34 + azure-mgmt-monitor/0.5.2 Azure-SDK-For-Python AZURECLI/2.0.49] + 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/metrics?timespan=2018-01-01T00%253A00%253A00%252B00%253A00%252F2031-09-10T00%253A00%253A00%252B00%253A00&interval=PT1M&metricnames=Ingress%2CEgress&top=10&api-version=2018-01-01 + response: + body: {string: '{"cost":0,"timespan":"2031-08-10T00:00:00Z/2031-09-10T00:00:00Z","interval":"PT1M","value":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/providers/Microsoft.Insights/metrics/Ingress","type":"Microsoft.Insights/metrics","name":{"value":"Ingress","localizedValue":"Ingress"},"unit":"Bytes","timeseries":[]},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/providers/Microsoft.Insights/metrics/Egress","type":"Microsoft.Insights/metrics","name":{"value":"Egress","localizedValue":"Egress"},"unit":"Bytes","timeseries":[]}],"namespace":"Microsoft.Storage/storageAccounts","resourceregion":"westus"}'} + headers: + __handlingserverid__: [shoeboxproxyustwo_shoeboxproxyustwo-red_MetricsMP_IN_8] + cache-control: [no-cache] + content-length: ['938'] + content-type: [application/json] + date: ['Thu, 18 Oct 2018 15:42:48 GMT'] + server: [Microsoft-IIS/8.5] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: ['Accept-Encoding,Accept-Encoding'] + x-aspnet-version: [4.0.30319] + x-content-type-options: [nosniff] + x-powered-by: [ASP.NET] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [monitor metrics list] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.6.1 (Windows-10-10.0.17763-SP0) msrest/0.6.1 msrest_azure/0.4.34 + azure-mgmt-monitor/0.5.2 Azure-SDK-For-Python AZURECLI/2.0.49] + 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/metrics?timespan=2011-04-25T00%253A00%253A00%252B00%253A00%252F2025-01-01T00%253A00%253A00%252B00%253A00&interval=PT1M&metricnames=Ingress%2CEgress&top=10&api-version=2018-01-01 + response: + body: {string: '{"cost":0,"timespan":"2024-12-01T00:00:00Z/2025-01-01T00:00:00Z","interval":"PT1M","value":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/providers/Microsoft.Insights/metrics/Ingress","type":"Microsoft.Insights/metrics","name":{"value":"Ingress","localizedValue":"Ingress"},"unit":"Bytes","timeseries":[]},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/providers/Microsoft.Insights/metrics/Egress","type":"Microsoft.Insights/metrics","name":{"value":"Egress","localizedValue":"Egress"},"unit":"Bytes","timeseries":[]}],"namespace":"Microsoft.Storage/storageAccounts","resourceregion":"westus"}'} + headers: + __handlingserverid__: [shoeboxproxyustwo_shoeboxproxyustwo-red_MetricsMP_IN_8] cache-control: [no-cache] content-length: ['938'] content-type: [application/json] - date: ['Thu, 15 Mar 2018 16:43:01 GMT'] + date: ['Thu, 18 Oct 2018 15:42:48 GMT'] server: [Microsoft-IIS/8.5] strict-transport-security: [max-age=31536000; includeSubDomains] transfer-encoding: [chunked] @@ -224,9 +308,8 @@ interactions: Connection: [keep-alive] Content-Length: ['0'] Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.6.1 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.27 - msrest_azure/0.4.22 resourcemanagementclient/1.2.1 Azure-SDK-For-Python - AZURECLI/2.0.30] + User-Agent: [python/3.6.1 (Windows-10-10.0.17763-SP0) msrest/0.6.1 msrest_azure/0.4.34 + resourcemanagementclient/2.0.0 Azure-SDK-For-Python AZURECLI/2.0.49] accept-language: [en-US] method: DELETE uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001?api-version=2018-05-01 @@ -235,12 +318,12 @@ interactions: headers: cache-control: [no-cache] content-length: ['0'] - date: ['Thu, 15 Mar 2018 16:43:02 GMT'] + date: ['Thu, 18 Oct 2018 15:42:50 GMT'] expires: ['-1'] - location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/operationresults/eyJqb2JJZCI6IlJFU09VUkNFR1JPVVBERUxFVElPTkpPQi1DTElURVNUOjJFUkcyWlNQM0NKSFRPNEoyRUM3SFhBSE1KRElZQkdYRUVFSUNJQnxCRkExN0JGQTZFNkMwOEQ0LVNPVVRIQ0VOVFJBTFVTIiwiam9iTG9jYXRpb24iOiJzb3V0aGNlbnRyYWx1cyJ9?api-version=2018-05-01'] + location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/operationresults/eyJqb2JJZCI6IlJFU09VUkNFR1JPVVBERUxFVElPTkpPQi1DTElURVNUOjJFUkdDUEdISVJDS0VTQVRHN01WUTQ3NTVIRklaQjNIS0dMVElKN3xGOTFBN0E4ODBGREI3NjUzLVNPVVRIQ0VOVFJBTFVTIiwiam9iTG9jYXRpb24iOiJzb3V0aGNlbnRyYWx1cyJ9?api-version=2018-05-01'] pragma: [no-cache] strict-transport-security: [max-age=31536000; includeSubDomains] x-content-type-options: [nosniff] - x-ms-ratelimit-remaining-subscription-writes: ['1198'] + x-ms-ratelimit-remaining-subscription-deletes: ['14999'] status: {code: 202, message: Accepted} version: 1 diff --git a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/test_activity_log_components.py b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/test_activity_log_components.py deleted file mode 100644 index 42930c3ea46..00000000000 --- a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/test_activity_log_components.py +++ /dev/null @@ -1,72 +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 -import re - -from knack.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) diff --git a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/test_activity_log_scenario.py b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/test_activity_log_scenario.py index 53d42b20d2d..cf2d4008207 100644 --- a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/test_activity_log_scenario.py +++ b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/test_activity_log_scenario.py @@ -4,20 +4,18 @@ # -------------------------------------------------------------------------------------------- from time import sleep -from azure.cli.testsdk import LiveScenarioTest, ResourceGroupPreparer, StorageAccountPreparer +from azure.cli.testsdk import ScenarioTest, ResourceGroupPreparer, StorageAccountPreparer +from azure_devtools.scenario_tests import AllowLargeResponse + +from knack.util import CLIError # This is a live test because the start and end time can't be determined dynamically -class TestActivityLogScenarios(LiveScenarioTest): +class TestActivityLogScenarios(ScenarioTest): + + @AllowLargeResponse() @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.') + with self.assertRaisesRegexp(CLIError, 'start time cannot be more than 90 days in the past'): + self.cmd('monitor activity-log list --start-time 2018-01-01T00:00:00Z --end-time 2999-01-01T00:00:00Z') diff --git a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/test_monitor_metrics.py b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/test_monitor_metrics.py index a77f921dc8c..308e27bae17 100644 --- a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/test_monitor_metrics.py +++ b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/test_monitor_metrics.py @@ -13,5 +13,9 @@ def test_monitor_metrics_scenario(self, resource_group, storage_account): self.kwargs.update({}) self.kwargs['sa_id'] = self.cmd('az storage account show -n {sa} -g {rg}').get_output_in_json()['id'] self.cmd('az monitor metrics list-definitions --resource {sa_id} --namespace Microsoft.Storage/storageAccounts') - self.cmd('az monitor metrics list --resource {sa_id} --namespace Microsoft.Storage/storageAccounts --metrics "Ingress" "Egress" --start-time 2018-01-01T00:00:00Z --end-time 2999-01-01T00:00:00Z', + self.cmd('az monitor metrics list --resource {sa_id} --namespace Microsoft.Storage/storageAccounts --metrics Ingress Egress --start-time 2018-01-01T00:00:00Z --end-time 2999-01-01T00:00:00Z', + checks=self.check('length(@.value)', 2)) + self.cmd('az monitor metrics list --resource {sa_id} --metrics Ingress Egress --start-time 2018-01-01 00:00:00 +00:00 --offset 5000d', + checks=self.check('length(@.value)', 2)) + self.cmd('az monitor metrics list --resource {sa_id} --metrics Ingress Egress --end-time 2025-01-01 00:00:00 +00:00 --offset 5000d', checks=self.check('length(@.value)', 2)) diff --git a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/util.py b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/util.py index 75d681015ae..8d43de79375 100644 --- a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/util.py +++ b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/util.py @@ -55,20 +55,3 @@ def get_autoscale_scale_direction_map(): return {'to': ScaleDirection.none, 'out': ScaleDirection.increase, 'in': ScaleDirection.decrease} # endregion - - -def validate_time_range_and_add_defaults(start_time, end_time, formatter='startTime eq {} and endTime eq {}'): - from datetime import datetime, timedelta - 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')) diff --git a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/validators.py b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/validators.py index 7fbf18c13b1..881fee90ea6 100644 --- a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/validators.py +++ b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/validators.py @@ -67,7 +67,7 @@ def _validate_weekly_recurrence(namespace): def validate_autoscale_timegrain(namespace): from azure.mgmt.monitor.models import MetricTrigger - from azure.cli.command_modules.monitor.actions import period_type + from azure.cli.command_modules.monitor.actions import get_period_type from azure.cli.command_modules.monitor.util import get_autoscale_statistic_map values = namespace.timegrain @@ -77,10 +77,10 @@ def validate_autoscale_timegrain(namespace): values = values[0].split(' ') name_offset = 0 try: - time_grain = period_type(values[1]) + time_grain = get_period_type()(values[1]) name_offset += 1 except ValueError: - time_grain = period_type('1m') + time_grain = get_period_type()('1m') try: statistic = get_autoscale_statistic_map()[values[0]] name_offset += 1 @@ -231,49 +231,16 @@ 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 +def validate_metric_dimension(namespace): - 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 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: + if not namespace.dimension: return - param_filter = ns.pop('filter', None) - if param_filter: + if namespace.filters: from knack.util import CLIError raise CLIError('usage: --dimension and --filter parameters are mutually exclusive.') - ns['filter'] = ' and '.join("{} eq '*'".format(d) for d in dimensions) - - -def validate_metric_names(namespace): - if namespace.metricnames: - namespace.metricnames = ','.join(namespace.metricnames) + namespace.filters = ' and '.join("{} eq '*'".format(d) for d in namespace.dimension) def process_webhook_prop(namespace):