diff --git a/src/command_modules/azure-cli-monitor/HISTORY.rst b/src/command_modules/azure-cli-monitor/HISTORY.rst index b6191578c71..8e39a4a6926 100644 --- a/src/command_modules/azure-cli-monitor/HISTORY.rst +++ b/src/command_modules/azure-cli-monitor/HISTORY.rst @@ -3,6 +3,10 @@ Release History =============== +0.2.6 ++++++ +* `monitor metrics alert create/update`: `--condition` now supports metric names which include characters forward-slash (/) and period (.). + 0.2.5 +++++ * `monitor activity-log list`: 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 2ba92625235..fb505489e5d 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 @@ -326,6 +326,8 @@ helps['monitor diagnostic-settings create'] = """ type: command short-summary: Create diagnostic settings for the specified resource. + long-summary: > + For more information, visit: https://docs.microsoft.com/en-us/rest/api/monitor/diagnosticsettings/createorupdate#metricsettings parameters: - name: --name -n short-summary: The name of the diagnostic settings. @@ -351,6 +353,31 @@ Name or ID an event hub. If none is specified, the default event hub will be selected. - name: --event-hub-rule short-summary: Name or ID of the event hub authorization rule. + examples: + - name: Create diagnostic settings with EventHub. + text: | + az monitor diagnostic-settings create --resource {ID} -n {name} + --event-hub-rule {eventHubRuleID} --storage-account {storageAccount} + --logs '[ + { + "category": "WorkflowRuntime", + "enabled": true, + "retentionPolicy": { + "enabled": false, + "days": 0 + } + } + ]' + --metrics '[ + { + "category": "WorkflowRuntime", + "enabled": true, + "retentionPolicy": { + "enabled": false, + "days": 0 + } + } + ]' """ helps['monitor diagnostic-settings update'] = """ type: command 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 3db63944204..4c9fdcf5bc4 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 @@ -4,8 +4,8 @@ # -------------------------------------------------------------------------------------------- import argparse - import antlr4 +from knack.util import CLIError from azure.cli.command_modules.monitor.util import ( get_aggregation_map, get_operator_map, get_autoscale_operator_map, @@ -16,7 +16,6 @@ def timezone_name_type(value): from azure.cli.command_modules.monitor._autoscale_util import AUTOSCALE_TIMEZONES zone = next((x['name'] for x in AUTOSCALE_TIMEZONES if x['name'].lower() == value.lower()), None) if not zone: - from knack.util import CLIError raise CLIError( "Invalid time zone: '{}'. Run 'az monitor autoscale profile list-timezones' for values.".format(value)) return zone @@ -33,7 +32,6 @@ def timezone_offset_type(value): hour = int(hour) if hour > 14 or hour < -12: - from knack.util import CLIError raise CLIError('Offset out of range: -12 to +14') if hour >= 0 and hour < 10: @@ -96,6 +94,10 @@ def __call__(self, parser, namespace, values, option_string=None): from azure.cli.command_modules.monitor.grammar import ( MetricAlertConditionLexer, MetricAlertConditionParser, MetricAlertConditionValidator) + usage = 'usage error: --condition {avg,min,max,total} [NAMESPACE.]METRIC {=,!=,>,>=,<,<=} THRESHOLD\n' \ + ' [where DIMENSION {includes,excludes} VALUE [or VALUE ...]\n' \ + ' [and DIMENSION {includes,excludes} VALUE [or VALUE ...] ...]]' + string_val = ' '.join(values) lexer = MetricAlertConditionLexer(antlr4.InputStream(string_val)) @@ -103,10 +105,16 @@ def __call__(self, parser, namespace, values, option_string=None): parser = MetricAlertConditionParser(stream) tree = parser.expression() - validator = MetricAlertConditionValidator() - walker = antlr4.ParseTreeWalker() - walker.walk(validator, tree) - metric_condition = validator.result() + try: + validator = MetricAlertConditionValidator() + walker = antlr4.ParseTreeWalker() + walker.walk(validator, tree) + metric_condition = validator.result() + for item in ['time_aggregation', 'metric_name', 'threshold', 'operator']: + if not getattr(metric_condition, item, None): + raise CLIError(usage) + except (AttributeError, TypeError, KeyError): + raise CLIError(usage) super(MetricAlertConditionAction, self).__call__(parser, namespace, metric_condition, option_string) @@ -136,7 +144,6 @@ def __call__(self, parser, namespace, values, option_string=None): # specified as a quoted expression values = values[0].split(' ') if len(values) < 5: - from knack.util import CLIError raise CLIError('usage error: --condition METRIC {>,>=,<,<=} THRESHOLD {avg,min,max,total,last} DURATION') metric_name = ' '.join(values[:-4]) operator = get_operator_map()[values[-4]] @@ -157,7 +164,6 @@ def __call__(self, parser, namespace, values, option_string=None): super(AlertAddAction, self).__call__(parser, namespace, action, option_string) def get_action(self, values, option_string): # pylint: disable=no-self-use - from knack.util import CLIError _type = values[0].lower() if _type == 'email': from azure.mgmt.monitor.models import RuleEmailAction @@ -182,7 +188,6 @@ def __call__(self, parser, namespace, values, option_string=None): def get_action(self, values, option_string): # pylint: disable=no-self-use # TYPE is artificially enforced to create consistency with the --add-action argument # but it could be enhanced to do additional validation in the future. - from knack.util import CLIError _type = values[0].lower() if _type not in ['email', 'webhook']: raise CLIError('usage error: {} TYPE KEY [KEY ...]'.format(option_string)) @@ -196,7 +201,6 @@ def __call__(self, parser, namespace, values, option_string=None): super(AutoscaleAddAction, self).__call__(parser, namespace, action, option_string) def get_action(self, values, option_string): # pylint: disable=no-self-use - from knack.util import CLIError _type = values[0].lower() if _type == 'email': from azure.mgmt.monitor.models import EmailNotification @@ -221,7 +225,6 @@ def __call__(self, parser, namespace, values, option_string=None): def get_action(self, values, option_string): # pylint: disable=no-self-use # TYPE is artificially enforced to create consistency with the --add-action argument # but it could be enhanced to do additional validation in the future. - from knack.util import CLIError _type = values[0].lower() if _type not in ['email', 'webhook']: raise CLIError('usage error: {} TYPE KEY [KEY ...]'.format(option_string)) @@ -243,7 +246,6 @@ def __call__(self, parser, namespace, values, option_string=None): aggregation = get_autoscale_aggregation_map()[values[-2].lower()] window = get_period_type()(values[-1]) except (IndexError, KeyError): - from knack.util import CLIError raise CLIError('usage error: --condition METRIC {==,!=,>,>=,<,<=} ' 'THRESHOLD {avg,min,max,total,count} PERIOD') condition = MetricTrigger( @@ -267,7 +269,6 @@ def __call__(self, parser, namespace, values, option_string=None): # specified as a quoted expression values = values[0].split(' ') if len(values) != 2: - from knack.util import CLIError raise CLIError('usage error: --scale {in,out,to} VALUE[%]') dir_val = values[0] amt_val = values[1] @@ -316,7 +317,6 @@ def deserialize_object(self, type_name, type_properties): class ActionGroupReceiverParameterAction(MultiObjectsDeserializeAction): def deserialize_object(self, type_name, type_properties): from azure.mgmt.monitor.models import EmailReceiver, SmsReceiver, WebhookReceiver - from knack.util import CLIError if type_name == 'email': try: diff --git a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/grammar/MetricAlertCondition.g4 b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/grammar/MetricAlertCondition.g4 index 45b448f064c..8926924f015 100644 --- a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/grammar/MetricAlertCondition.g4 +++ b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/grammar/MetricAlertCondition.g4 @@ -10,7 +10,7 @@ aggregation : WORD WHITESPACE ; namespace : WORD ; -metric : (WORD | WHITESPACE)+; +metric : (WORD | WHITESPACE | '.' | '/')+; operator : OPERATOR WHITESPACE ; @@ -69,3 +69,4 @@ QUOTE : ('\'' | '"') ; WHITESPACE : (' ' | '\t')+ ; NEWLINE : ('\r'? '\n' | '\r')+ ; WORD : (LOWERCASE | UPPERCASE | DIGIT | '_')+ ; + diff --git a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/grammar/MetricAlertCondition.tokens b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/grammar/MetricAlertCondition.tokens index bb37544df85..90ee6ad3e71 100644 --- a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/grammar/MetricAlertCondition.tokens +++ b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/grammar/MetricAlertCondition.tokens @@ -1,15 +1,17 @@ T__0=1 T__1=2 -WHERE=3 -AND=4 -IN=5 -IS=6 -OR=7 -OPERATOR=8 -NUMBER=9 -QUOTE=10 -WHITESPACE=11 -NEWLINE=12 -WORD=13 +T__2=3 +WHERE=4 +AND=5 +INCLUDES=6 +EXCLUDES=7 +OR=8 +OPERATOR=9 +NUMBER=10 +QUOTE=11 +WHITESPACE=12 +NEWLINE=13 +WORD=14 '.'=1 -','=2 +'/'=2 +','=3 diff --git a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/grammar/MetricAlertConditionLexer.py b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/grammar/MetricAlertConditionLexer.py index e108494ea7a..002e3463eeb 100644 --- a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/grammar/MetricAlertConditionLexer.py +++ b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/grammar/MetricAlertConditionLexer.py @@ -16,79 +16,81 @@ def serializedATN(): with StringIO() as buf: buf.write(u"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2") - buf.write(u"\17\u00b4\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6") + buf.write(u"\20\u00b8\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6") buf.write(u"\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4") buf.write(u"\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t") buf.write(u"\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27") buf.write(u"\4\30\t\30\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4") - buf.write(u"\35\t\35\4\36\t\36\4\37\t\37\3\2\3\2\3\3\3\3\3\4\3\4") - buf.write(u"\3\5\3\5\3\6\3\6\3\7\3\7\3\b\3\b\3\t\3\t\3\n\3\n\3\13") - buf.write(u"\3\13\3\f\3\f\3\r\3\r\3\16\3\16\3\17\3\17\3\20\3\20\3") - buf.write(u"\21\3\21\3\22\3\22\3\23\3\23\3\24\3\24\3\25\3\25\3\25") - buf.write(u"\3\25\3\25\3\25\3\26\3\26\3\26\3\26\3\27\3\27\3\27\3") - buf.write(u"\27\3\27\3\27\3\27\3\27\3\27\3\30\3\30\3\30\3\30\3\30") - buf.write(u"\3\30\3\30\3\30\3\30\3\31\3\31\3\31\3\32\3\32\3\32\3") - buf.write(u"\32\3\32\3\32\3\32\3\32\3\32\5\32\u008e\n\32\3\33\6\33") - buf.write(u"\u0091\n\33\r\33\16\33\u0092\3\33\3\33\6\33\u0097\n\33") - buf.write(u"\r\33\16\33\u0098\5\33\u009b\n\33\3\34\3\34\3\35\6\35") - buf.write(u"\u00a0\n\35\r\35\16\35\u00a1\3\36\5\36\u00a5\n\36\3\36") - buf.write(u"\3\36\6\36\u00a9\n\36\r\36\16\36\u00aa\3\37\3\37\3\37") - buf.write(u"\3\37\6\37\u00b1\n\37\r\37\16\37\u00b2\2\2 \3\3\5\4\7") - buf.write(u"\2\t\2\13\2\r\2\17\2\21\2\23\2\25\2\27\2\31\2\33\2\35") - buf.write(u"\2\37\2!\2#\2%\2\'\2)\5+\6-\7/\b\61\t\63\n\65\13\67\f") - buf.write(u"9\r;\16=\17\3\2\26\4\2CCcc\4\2EEee\4\2FFff\4\2GGgg\4") - buf.write(u"\2JJjj\4\2KKkk\4\2NNnn\4\2PPpp\4\2QQqq\4\2TTtt\4\2UU") - buf.write(u"uu\4\2WWww\4\2YYyy\4\2ZZzz\3\2\62;\3\2c|\3\2C\\\4\2.") - buf.write(u".\60\60\4\2$$))\4\2\13\13\"\"\2\u00b2\2\3\3\2\2\2\2\5") - buf.write(u"\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2") - buf.write(u"\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2") - buf.write(u"\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\3?\3\2\2\2\5A\3\2\2") - buf.write(u"\2\7C\3\2\2\2\tE\3\2\2\2\13G\3\2\2\2\rI\3\2\2\2\17K\3") - buf.write(u"\2\2\2\21M\3\2\2\2\23O\3\2\2\2\25Q\3\2\2\2\27S\3\2\2") - buf.write(u"\2\31U\3\2\2\2\33W\3\2\2\2\35Y\3\2\2\2\37[\3\2\2\2!]") - buf.write(u"\3\2\2\2#_\3\2\2\2%a\3\2\2\2\'c\3\2\2\2)e\3\2\2\2+k\3") - buf.write(u"\2\2\2-o\3\2\2\2/x\3\2\2\2\61\u0081\3\2\2\2\63\u008d") - buf.write(u"\3\2\2\2\65\u0090\3\2\2\2\67\u009c\3\2\2\29\u009f\3\2") - buf.write(u"\2\2;\u00a8\3\2\2\2=\u00b0\3\2\2\2?@\7\60\2\2@\4\3\2") - buf.write(u"\2\2AB\7.\2\2B\6\3\2\2\2CD\t\2\2\2D\b\3\2\2\2EF\t\3\2") - buf.write(u"\2F\n\3\2\2\2GH\t\4\2\2H\f\3\2\2\2IJ\t\5\2\2J\16\3\2") - buf.write(u"\2\2KL\t\6\2\2L\20\3\2\2\2MN\t\7\2\2N\22\3\2\2\2OP\t") - buf.write(u"\b\2\2P\24\3\2\2\2QR\t\t\2\2R\26\3\2\2\2ST\t\n\2\2T\30") - buf.write(u"\3\2\2\2UV\t\13\2\2V\32\3\2\2\2WX\t\f\2\2X\34\3\2\2\2") - buf.write(u"YZ\t\r\2\2Z\36\3\2\2\2[\\\t\16\2\2\\ \3\2\2\2]^\t\17") - buf.write(u"\2\2^\"\3\2\2\2_`\t\20\2\2`$\3\2\2\2ab\t\21\2\2b&\3\2") - buf.write(u"\2\2cd\t\22\2\2d(\3\2\2\2ef\5\37\20\2fg\5\17\b\2gh\5") - buf.write(u"\r\7\2hi\5\31\r\2ij\5\r\7\2j*\3\2\2\2kl\5\7\4\2lm\5\25") - buf.write(u"\13\2mn\5\13\6\2n,\3\2\2\2op\5\21\t\2pq\5\25\13\2qr\5") - buf.write(u"\t\5\2rs\5\23\n\2st\5\35\17\2tu\5\13\6\2uv\5\r\7\2vw") - buf.write(u"\5\33\16\2w.\3\2\2\2xy\5\r\7\2yz\5!\21\2z{\5\t\5\2{|") - buf.write(u"\5\23\n\2|}\5\35\17\2}~\5\13\6\2~\177\5\r\7\2\177\u0080") - buf.write(u"\5\33\16\2\u0080\60\3\2\2\2\u0081\u0082\5\27\f\2\u0082") - buf.write(u"\u0083\5\31\r\2\u0083\62\3\2\2\2\u0084\u008e\7>\2\2\u0085") - buf.write(u"\u0086\7>\2\2\u0086\u008e\7?\2\2\u0087\u008e\7?\2\2\u0088") - buf.write(u"\u0089\7@\2\2\u0089\u008e\7?\2\2\u008a\u008e\7@\2\2\u008b") - buf.write(u"\u008c\7#\2\2\u008c\u008e\7?\2\2\u008d\u0084\3\2\2\2") - buf.write(u"\u008d\u0085\3\2\2\2\u008d\u0087\3\2\2\2\u008d\u0088") - buf.write(u"\3\2\2\2\u008d\u008a\3\2\2\2\u008d\u008b\3\2\2\2\u008e") - buf.write(u"\64\3\2\2\2\u008f\u0091\5#\22\2\u0090\u008f\3\2\2\2\u0091") - buf.write(u"\u0092\3\2\2\2\u0092\u0090\3\2\2\2\u0092\u0093\3\2\2") - buf.write(u"\2\u0093\u009a\3\2\2\2\u0094\u0096\t\23\2\2\u0095\u0097") - buf.write(u"\5#\22\2\u0096\u0095\3\2\2\2\u0097\u0098\3\2\2\2\u0098") - buf.write(u"\u0096\3\2\2\2\u0098\u0099\3\2\2\2\u0099\u009b\3\2\2") - buf.write(u"\2\u009a\u0094\3\2\2\2\u009a\u009b\3\2\2\2\u009b\66\3") - buf.write(u"\2\2\2\u009c\u009d\t\24\2\2\u009d8\3\2\2\2\u009e\u00a0") - buf.write(u"\t\25\2\2\u009f\u009e\3\2\2\2\u00a0\u00a1\3\2\2\2\u00a1") - buf.write(u"\u009f\3\2\2\2\u00a1\u00a2\3\2\2\2\u00a2:\3\2\2\2\u00a3") - buf.write(u"\u00a5\7\17\2\2\u00a4\u00a3\3\2\2\2\u00a4\u00a5\3\2\2") - buf.write(u"\2\u00a5\u00a6\3\2\2\2\u00a6\u00a9\7\f\2\2\u00a7\u00a9") - buf.write(u"\7\17\2\2\u00a8\u00a4\3\2\2\2\u00a8\u00a7\3\2\2\2\u00a9") - buf.write(u"\u00aa\3\2\2\2\u00aa\u00a8\3\2\2\2\u00aa\u00ab\3\2\2") - buf.write(u"\2\u00ab<\3\2\2\2\u00ac\u00b1\5%\23\2\u00ad\u00b1\5\'") - buf.write(u"\24\2\u00ae\u00b1\5#\22\2\u00af\u00b1\7a\2\2\u00b0\u00ac") - buf.write(u"\3\2\2\2\u00b0\u00ad\3\2\2\2\u00b0\u00ae\3\2\2\2\u00b0") - buf.write(u"\u00af\3\2\2\2\u00b1\u00b2\3\2\2\2\u00b2\u00b0\3\2\2") - buf.write(u"\2\u00b2\u00b3\3\2\2\2\u00b3>\3\2\2\2\r\2\u008d\u0092") - buf.write(u"\u0098\u009a\u00a1\u00a4\u00a8\u00aa\u00b0\u00b2\2") + buf.write(u"\35\t\35\4\36\t\36\4\37\t\37\4 \t \3\2\3\2\3\3\3\3\3") + buf.write(u"\4\3\4\3\5\3\5\3\6\3\6\3\7\3\7\3\b\3\b\3\t\3\t\3\n\3") + buf.write(u"\n\3\13\3\13\3\f\3\f\3\r\3\r\3\16\3\16\3\17\3\17\3\20") + buf.write(u"\3\20\3\21\3\21\3\22\3\22\3\23\3\23\3\24\3\24\3\25\3") + buf.write(u"\25\3\26\3\26\3\26\3\26\3\26\3\26\3\27\3\27\3\27\3\27") + buf.write(u"\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\31\3") + buf.write(u"\31\3\31\3\31\3\31\3\31\3\31\3\31\3\31\3\32\3\32\3\32") + buf.write(u"\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\33\5\33\u0092") + buf.write(u"\n\33\3\34\6\34\u0095\n\34\r\34\16\34\u0096\3\34\3\34") + buf.write(u"\6\34\u009b\n\34\r\34\16\34\u009c\5\34\u009f\n\34\3\35") + buf.write(u"\3\35\3\36\6\36\u00a4\n\36\r\36\16\36\u00a5\3\37\5\37") + buf.write(u"\u00a9\n\37\3\37\3\37\6\37\u00ad\n\37\r\37\16\37\u00ae") + buf.write(u"\3 \3 \3 \3 \6 \u00b5\n \r \16 \u00b6\2\2!\3\3\5\4\7") + buf.write(u"\5\t\2\13\2\r\2\17\2\21\2\23\2\25\2\27\2\31\2\33\2\35") + buf.write(u"\2\37\2!\2#\2%\2\'\2)\2+\6-\7/\b\61\t\63\n\65\13\67\f") + buf.write(u"9\r;\16=\17?\20\3\2\26\4\2CCcc\4\2EEee\4\2FFff\4\2GG") + buf.write(u"gg\4\2JJjj\4\2KKkk\4\2NNnn\4\2PPpp\4\2QQqq\4\2TTtt\4") + buf.write(u"\2UUuu\4\2WWww\4\2YYyy\4\2ZZzz\3\2\62;\3\2c|\3\2C\\\4") + buf.write(u"\2..\60\60\4\2$$))\4\2\13\13\"\"\2\u00b6\2\3\3\2\2\2") + buf.write(u"\2\5\3\2\2\2\2\7\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2") + buf.write(u"\2\2\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2") + buf.write(u"\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3\2\2\2\3A\3") + buf.write(u"\2\2\2\5C\3\2\2\2\7E\3\2\2\2\tG\3\2\2\2\13I\3\2\2\2\r") + buf.write(u"K\3\2\2\2\17M\3\2\2\2\21O\3\2\2\2\23Q\3\2\2\2\25S\3\2") + buf.write(u"\2\2\27U\3\2\2\2\31W\3\2\2\2\33Y\3\2\2\2\35[\3\2\2\2") + buf.write(u"\37]\3\2\2\2!_\3\2\2\2#a\3\2\2\2%c\3\2\2\2\'e\3\2\2\2") + buf.write(u")g\3\2\2\2+i\3\2\2\2-o\3\2\2\2/s\3\2\2\2\61|\3\2\2\2") + buf.write(u"\63\u0085\3\2\2\2\65\u0091\3\2\2\2\67\u0094\3\2\2\29") + buf.write(u"\u00a0\3\2\2\2;\u00a3\3\2\2\2=\u00ac\3\2\2\2?\u00b4\3") + buf.write(u"\2\2\2AB\7\60\2\2B\4\3\2\2\2CD\7\61\2\2D\6\3\2\2\2EF") + buf.write(u"\7.\2\2F\b\3\2\2\2GH\t\2\2\2H\n\3\2\2\2IJ\t\3\2\2J\f") + buf.write(u"\3\2\2\2KL\t\4\2\2L\16\3\2\2\2MN\t\5\2\2N\20\3\2\2\2") + buf.write(u"OP\t\6\2\2P\22\3\2\2\2QR\t\7\2\2R\24\3\2\2\2ST\t\b\2") + buf.write(u"\2T\26\3\2\2\2UV\t\t\2\2V\30\3\2\2\2WX\t\n\2\2X\32\3") + buf.write(u"\2\2\2YZ\t\13\2\2Z\34\3\2\2\2[\\\t\f\2\2\\\36\3\2\2\2") + buf.write(u"]^\t\r\2\2^ \3\2\2\2_`\t\16\2\2`\"\3\2\2\2ab\t\17\2\2") + buf.write(u"b$\3\2\2\2cd\t\20\2\2d&\3\2\2\2ef\t\21\2\2f(\3\2\2\2") + buf.write(u"gh\t\22\2\2h*\3\2\2\2ij\5!\21\2jk\5\21\t\2kl\5\17\b\2") + buf.write(u"lm\5\33\16\2mn\5\17\b\2n,\3\2\2\2op\5\t\5\2pq\5\27\f") + buf.write(u"\2qr\5\r\7\2r.\3\2\2\2st\5\23\n\2tu\5\27\f\2uv\5\13\6") + buf.write(u"\2vw\5\25\13\2wx\5\37\20\2xy\5\r\7\2yz\5\17\b\2z{\5\35") + buf.write(u"\17\2{\60\3\2\2\2|}\5\17\b\2}~\5#\22\2~\177\5\13\6\2") + buf.write(u"\177\u0080\5\25\13\2\u0080\u0081\5\37\20\2\u0081\u0082") + buf.write(u"\5\r\7\2\u0082\u0083\5\17\b\2\u0083\u0084\5\35\17\2\u0084") + buf.write(u"\62\3\2\2\2\u0085\u0086\5\31\r\2\u0086\u0087\5\33\16") + buf.write(u"\2\u0087\64\3\2\2\2\u0088\u0092\7>\2\2\u0089\u008a\7") + buf.write(u">\2\2\u008a\u0092\7?\2\2\u008b\u0092\7?\2\2\u008c\u008d") + buf.write(u"\7@\2\2\u008d\u0092\7?\2\2\u008e\u0092\7@\2\2\u008f\u0090") + buf.write(u"\7#\2\2\u0090\u0092\7?\2\2\u0091\u0088\3\2\2\2\u0091") + buf.write(u"\u0089\3\2\2\2\u0091\u008b\3\2\2\2\u0091\u008c\3\2\2") + buf.write(u"\2\u0091\u008e\3\2\2\2\u0091\u008f\3\2\2\2\u0092\66\3") + buf.write(u"\2\2\2\u0093\u0095\5%\23\2\u0094\u0093\3\2\2\2\u0095") + buf.write(u"\u0096\3\2\2\2\u0096\u0094\3\2\2\2\u0096\u0097\3\2\2") + buf.write(u"\2\u0097\u009e\3\2\2\2\u0098\u009a\t\23\2\2\u0099\u009b") + buf.write(u"\5%\23\2\u009a\u0099\3\2\2\2\u009b\u009c\3\2\2\2\u009c") + buf.write(u"\u009a\3\2\2\2\u009c\u009d\3\2\2\2\u009d\u009f\3\2\2") + buf.write(u"\2\u009e\u0098\3\2\2\2\u009e\u009f\3\2\2\2\u009f8\3\2") + buf.write(u"\2\2\u00a0\u00a1\t\24\2\2\u00a1:\3\2\2\2\u00a2\u00a4") + buf.write(u"\t\25\2\2\u00a3\u00a2\3\2\2\2\u00a4\u00a5\3\2\2\2\u00a5") + buf.write(u"\u00a3\3\2\2\2\u00a5\u00a6\3\2\2\2\u00a6<\3\2\2\2\u00a7") + buf.write(u"\u00a9\7\17\2\2\u00a8\u00a7\3\2\2\2\u00a8\u00a9\3\2\2") + buf.write(u"\2\u00a9\u00aa\3\2\2\2\u00aa\u00ad\7\f\2\2\u00ab\u00ad") + buf.write(u"\7\17\2\2\u00ac\u00a8\3\2\2\2\u00ac\u00ab\3\2\2\2\u00ad") + buf.write(u"\u00ae\3\2\2\2\u00ae\u00ac\3\2\2\2\u00ae\u00af\3\2\2") + buf.write(u"\2\u00af>\3\2\2\2\u00b0\u00b5\5\'\24\2\u00b1\u00b5\5") + buf.write(u")\25\2\u00b2\u00b5\5%\23\2\u00b3\u00b5\7a\2\2\u00b4\u00b0") + buf.write(u"\3\2\2\2\u00b4\u00b1\3\2\2\2\u00b4\u00b2\3\2\2\2\u00b4") + buf.write(u"\u00b3\3\2\2\2\u00b5\u00b6\3\2\2\2\u00b6\u00b4\3\2\2") + buf.write(u"\2\u00b6\u00b7\3\2\2\2\u00b7@\3\2\2\2\r\2\u0091\u0096") + buf.write(u"\u009c\u009e\u00a5\u00a8\u00ac\u00ae\u00b4\u00b6\2") return buf.getvalue() @@ -100,34 +102,35 @@ class MetricAlertConditionLexer(Lexer): T__0 = 1 T__1 = 2 - WHERE = 3 - AND = 4 - INCLUDES = 5 - EXCLUDES = 6 - OR = 7 - OPERATOR = 8 - NUMBER = 9 - QUOTE = 10 - WHITESPACE = 11 - NEWLINE = 12 - WORD = 13 + T__2 = 3 + WHERE = 4 + AND = 5 + INCLUDES = 6 + EXCLUDES = 7 + OR = 8 + OPERATOR = 9 + NUMBER = 10 + QUOTE = 11 + WHITESPACE = 12 + NEWLINE = 13 + WORD = 14 channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ] modeNames = [ u"DEFAULT_MODE" ] literalNames = [ u"", - u"'.'", u"','" ] + u"'.'", u"'/'", u"','" ] symbolicNames = [ u"", u"WHERE", u"AND", u"INCLUDES", u"EXCLUDES", u"OR", u"OPERATOR", u"NUMBER", u"QUOTE", u"WHITESPACE", u"NEWLINE", u"WORD" ] - ruleNames = [ u"T__0", u"T__1", u"A", u"C", u"D", u"E", u"H", u"I", - u"L", u"N", u"O", u"R", u"S", u"U", u"W", u"X", u"DIGIT", - u"LOWERCASE", u"UPPERCASE", u"WHERE", u"AND", u"INCLUDES", - u"EXCLUDES", u"OR", u"OPERATOR", u"NUMBER", u"QUOTE", - u"WHITESPACE", u"NEWLINE", u"WORD" ] + ruleNames = [ u"T__0", u"T__1", u"T__2", u"A", u"C", u"D", u"E", u"H", + u"I", u"L", u"N", u"O", u"R", u"S", u"U", u"W", u"X", + u"DIGIT", u"LOWERCASE", u"UPPERCASE", u"WHERE", u"AND", + u"INCLUDES", u"EXCLUDES", u"OR", u"OPERATOR", u"NUMBER", + u"QUOTE", u"WHITESPACE", u"NEWLINE", u"WORD" ] grammarFileName = u"MetricAlertCondition.g4" diff --git a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/grammar/MetricAlertConditionParser.py b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/grammar/MetricAlertConditionParser.py index 33a2037ffd3..3179f830020 100644 --- a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/grammar/MetricAlertConditionParser.py +++ b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/grammar/MetricAlertConditionParser.py @@ -15,7 +15,7 @@ def serializedATN(): with StringIO() as buf: buf.write(u"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3") - buf.write(u"\17{\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") + buf.write(u"\20{\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") buf.write(u"\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r\t\r\4") buf.write(u"\16\t\16\4\17\t\17\4\20\t\20\3\2\3\2\3\2\3\2\7\2%\n\2") buf.write(u"\f\2\16\2(\13\2\3\2\3\2\3\2\3\2\3\2\3\2\5\2\60\n\2\3") @@ -26,32 +26,32 @@ def serializedATN(): buf.write(u"\13\3\13\3\f\3\f\3\f\3\r\3\r\3\r\3\16\3\16\3\16\3\17") buf.write(u"\3\17\3\17\3\17\7\17q\n\17\f\17\16\17t\13\17\3\20\6\20") buf.write(u"w\n\20\r\20\16\20x\3\20\2\2\21\2\4\6\b\n\f\16\20\22\24") - buf.write(u"\26\30\32\34\36\2\7\4\2\r\r\17\17\4\2\4\4\6\6\3\2\7\b") - buf.write(u"\4\2\4\4\t\t\5\2\13\13\r\r\17\17\2s\2 \3\2\2\2\4@\3\2") - buf.write(u"\2\2\6C\3\2\2\2\bF\3\2\2\2\nJ\3\2\2\2\fM\3\2\2\2\16O") - buf.write(u"\3\2\2\2\20R\3\2\2\2\22\\\3\2\2\2\24`\3\2\2\2\26c\3\2") - buf.write(u"\2\2\30f\3\2\2\2\32i\3\2\2\2\34l\3\2\2\2\36v\3\2\2\2") - buf.write(u" &\5\4\3\2!\"\5\6\4\2\"#\7\3\2\2#%\3\2\2\2$!\3\2\2\2") - buf.write(u"%(\3\2\2\2&$\3\2\2\2&\'\3\2\2\2\'/\3\2\2\2(&\3\2\2\2") - buf.write(u")*\7\f\2\2*+\5\b\5\2+,\7\f\2\2,-\7\r\2\2-\60\3\2\2\2") - buf.write(u".\60\5\b\5\2/)\3\2\2\2/.\3\2\2\2\60\61\3\2\2\2\61\62") - buf.write(u"\5\n\6\2\62\67\5\f\7\2\63\64\7\r\2\2\64\66\5\20\t\2\65") - buf.write(u"\63\3\2\2\2\669\3\2\2\2\67\65\3\2\2\2\678\3\2\2\28=\3") - buf.write(u"\2\2\29\67\3\2\2\2:<\7\16\2\2;:\3\2\2\2\3\2\2\2>\3\3\2\2\2?=\3\2\2\2@A\7\17\2\2AB\7") - buf.write(u"\r\2\2B\5\3\2\2\2CD\7\17\2\2D\7\3\2\2\2EG\t\2\2\2FE\3") - buf.write(u"\2\2\2GH\3\2\2\2HF\3\2\2\2HI\3\2\2\2I\t\3\2\2\2JK\7\n") - buf.write(u"\2\2KL\7\r\2\2L\13\3\2\2\2MN\7\13\2\2N\r\3\2\2\2OP\7") - buf.write(u"\5\2\2PQ\7\r\2\2Q\17\3\2\2\2RS\5\16\b\2SY\5\22\n\2TU") - buf.write(u"\5\24\13\2UV\5\22\n\2VX\3\2\2\2WT\3\2\2\2X[\3\2\2\2Y") - buf.write(u"W\3\2\2\2YZ\3\2\2\2Z\21\3\2\2\2[Y\3\2\2\2\\]\5\32\16") - buf.write(u"\2]^\5\26\f\2^_\5\34\17\2_\23\3\2\2\2`a\t\3\2\2ab\7\r") - buf.write(u"\2\2b\25\3\2\2\2cd\t\4\2\2de\7\r\2\2e\27\3\2\2\2fg\t") - buf.write(u"\5\2\2gh\7\r\2\2h\31\3\2\2\2ij\7\17\2\2jk\7\r\2\2k\33") - buf.write(u"\3\2\2\2lr\5\36\20\2mn\5\30\r\2no\5\36\20\2oq\3\2\2\2") - buf.write(u"pm\3\2\2\2qt\3\2\2\2rp\3\2\2\2rs\3\2\2\2s\35\3\2\2\2") - buf.write(u"tr\3\2\2\2uw\t\6\2\2vu\3\2\2\2wx\3\2\2\2xv\3\2\2\2xy") - buf.write(u"\3\2\2\2y\37\3\2\2\2\n&/\67=HYrx") + buf.write(u"\26\30\32\34\36\2\7\5\2\3\4\16\16\20\20\4\2\5\5\7\7\3") + buf.write(u"\2\b\t\4\2\5\5\n\n\5\2\f\f\16\16\20\20\2s\2 \3\2\2\2") + buf.write(u"\4@\3\2\2\2\6C\3\2\2\2\bF\3\2\2\2\nJ\3\2\2\2\fM\3\2\2") + buf.write(u"\2\16O\3\2\2\2\20R\3\2\2\2\22\\\3\2\2\2\24`\3\2\2\2\26") + buf.write(u"c\3\2\2\2\30f\3\2\2\2\32i\3\2\2\2\34l\3\2\2\2\36v\3\2") + buf.write(u"\2\2 &\5\4\3\2!\"\5\6\4\2\"#\7\3\2\2#%\3\2\2\2$!\3\2") + buf.write(u"\2\2%(\3\2\2\2&$\3\2\2\2&\'\3\2\2\2\'/\3\2\2\2(&\3\2") + buf.write(u"\2\2)*\7\r\2\2*+\5\b\5\2+,\7\r\2\2,-\7\16\2\2-\60\3\2") + buf.write(u"\2\2.\60\5\b\5\2/)\3\2\2\2/.\3\2\2\2\60\61\3\2\2\2\61") + buf.write(u"\62\5\n\6\2\62\67\5\f\7\2\63\64\7\16\2\2\64\66\5\20\t") + buf.write(u"\2\65\63\3\2\2\2\669\3\2\2\2\67\65\3\2\2\2\678\3\2\2") + buf.write(u"\28=\3\2\2\29\67\3\2\2\2:<\7\17\2\2;:\3\2\2\2\3\2\2\2>\3\3\2\2\2?=\3\2\2\2@A\7\20\2") + buf.write(u"\2AB\7\16\2\2B\5\3\2\2\2CD\7\20\2\2D\7\3\2\2\2EG\t\2") + buf.write(u"\2\2FE\3\2\2\2GH\3\2\2\2HF\3\2\2\2HI\3\2\2\2I\t\3\2\2") + buf.write(u"\2JK\7\13\2\2KL\7\16\2\2L\13\3\2\2\2MN\7\f\2\2N\r\3\2") + buf.write(u"\2\2OP\7\6\2\2PQ\7\16\2\2Q\17\3\2\2\2RS\5\16\b\2SY\5") + buf.write(u"\22\n\2TU\5\24\13\2UV\5\22\n\2VX\3\2\2\2WT\3\2\2\2X[") + buf.write(u"\3\2\2\2YW\3\2\2\2YZ\3\2\2\2Z\21\3\2\2\2[Y\3\2\2\2\\") + buf.write(u"]\5\32\16\2]^\5\26\f\2^_\5\34\17\2_\23\3\2\2\2`a\t\3") + buf.write(u"\2\2ab\7\16\2\2b\25\3\2\2\2cd\t\4\2\2de\7\16\2\2e\27") + buf.write(u"\3\2\2\2fg\t\5\2\2gh\7\16\2\2h\31\3\2\2\2ij\7\20\2\2") + buf.write(u"jk\7\16\2\2k\33\3\2\2\2lr\5\36\20\2mn\5\30\r\2no\5\36") + buf.write(u"\20\2oq\3\2\2\2pm\3\2\2\2qt\3\2\2\2rp\3\2\2\2rs\3\2\2") + buf.write(u"\2s\35\3\2\2\2tr\3\2\2\2uw\t\6\2\2vu\3\2\2\2wx\3\2\2") + buf.write(u"\2xv\3\2\2\2xy\3\2\2\2y\37\3\2\2\2\n&/\67=HYrx") return buf.getvalue() @@ -65,11 +65,12 @@ class MetricAlertConditionParser ( Parser ): sharedContextCache = PredictionContextCache() - literalNames = [ u"", u"'.'", u"','" ] + literalNames = [ u"", u"'.'", u"'/'", u"','" ] - symbolicNames = [ u"", u"", u"", u"WHERE", - u"AND", u"INCLUDES", u"EXCLUDES", u"OR", u"OPERATOR", - u"NUMBER", u"QUOTE", u"WHITESPACE", u"NEWLINE", u"WORD" ] + symbolicNames = [ u"", u"", u"", u"", + u"WHERE", u"AND", u"INCLUDES", u"EXCLUDES", u"OR", + u"OPERATOR", u"NUMBER", u"QUOTE", u"WHITESPACE", u"NEWLINE", + u"WORD" ] RULE_expression = 0 RULE_aggregation = 1 @@ -95,17 +96,18 @@ class MetricAlertConditionParser ( Parser ): EOF = Token.EOF T__0=1 T__1=2 - WHERE=3 - AND=4 - INCLUDES=5 - EXCLUDES=6 - OR=7 - OPERATOR=8 - NUMBER=9 - QUOTE=10 - WHITESPACE=11 - NEWLINE=12 - WORD=13 + T__2=3 + WHERE=4 + AND=5 + INCLUDES=6 + EXCLUDES=7 + OR=8 + OPERATOR=9 + NUMBER=10 + QUOTE=11 + WHITESPACE=12 + NEWLINE=13 + WORD=14 def __init__(self, input, output=sys.stdout): super(MetricAlertConditionParser, self).__init__(input, output=output) @@ -218,7 +220,7 @@ def expression(self): self.state = 42 self.match(MetricAlertConditionParser.WHITESPACE) pass - elif token in [MetricAlertConditionParser.WHITESPACE, MetricAlertConditionParser.WORD]: + elif token in [MetricAlertConditionParser.T__0, MetricAlertConditionParser.T__1, MetricAlertConditionParser.WHITESPACE, MetricAlertConditionParser.WORD]: self.state = 44 self.metric() pass @@ -387,7 +389,7 @@ def metric(self): while True: self.state = 67 _la = self._input.LA(1) - if not(_la==MetricAlertConditionParser.WHITESPACE or _la==MetricAlertConditionParser.WORD): + if not((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << MetricAlertConditionParser.T__0) | (1 << MetricAlertConditionParser.T__1) | (1 << MetricAlertConditionParser.WHITESPACE) | (1 << MetricAlertConditionParser.WORD))) != 0)): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) @@ -395,7 +397,7 @@ def metric(self): self.state = 70 self._errHandler.sync(self) _la = self._input.LA(1) - if not (_la==MetricAlertConditionParser.WHITESPACE or _la==MetricAlertConditionParser.WORD): + if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << MetricAlertConditionParser.T__0) | (1 << MetricAlertConditionParser.T__1) | (1 << MetricAlertConditionParser.WHITESPACE) | (1 << MetricAlertConditionParser.WORD))) != 0)): break except RecognitionException as re: @@ -585,7 +587,7 @@ def dimensions(self): self.state = 87 self._errHandler.sync(self) _la = self._input.LA(1) - while _la==MetricAlertConditionParser.T__1 or _la==MetricAlertConditionParser.AND: + while _la==MetricAlertConditionParser.T__2 or _la==MetricAlertConditionParser.AND: self.state = 82 self.dim_separator() self.state = 83 @@ -689,7 +691,7 @@ def dim_separator(self): self.enterOuterAlt(localctx, 1) self.state = 94 _la = self._input.LA(1) - if not(_la==MetricAlertConditionParser.T__1 or _la==MetricAlertConditionParser.AND): + if not(_la==MetricAlertConditionParser.T__2 or _la==MetricAlertConditionParser.AND): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) @@ -792,7 +794,7 @@ def dim_val_separator(self): self.enterOuterAlt(localctx, 1) self.state = 100 _la = self._input.LA(1) - if not(_la==MetricAlertConditionParser.T__1 or _la==MetricAlertConditionParser.OR): + if not(_la==MetricAlertConditionParser.T__2 or _la==MetricAlertConditionParser.OR): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) diff --git a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/test_monitor_unittest.py b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/test_monitor_unittest.py index ce6fb1a769e..6c96050f5c3 100644 --- a/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/test_monitor_unittest.py +++ b/src/command_modules/azure-cli-monitor/azure/cli/command_modules/monitor/tests/latest/test_monitor_unittest.py @@ -88,3 +88,66 @@ def test_monitor_resource_id(self): self.assertFalse(hasattr(ns, 'namespace')) self.assertFalse(hasattr(ns, 'parent')) self.assertFalse(hasattr(ns, 'resource_type')) + + +class MonitorMetricAlertActionTest(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 + return Namespace() + + def call_condition(self, ns, value): + from azure.cli.command_modules.monitor.actions import MetricAlertConditionAction + MetricAlertConditionAction('--condition', 'condition').__call__(None, ns, value.split(), '--condition') + + def check_condition(self, ns, time_aggregation, metric_namespace, metric_name, operator, threshold): + prop = ns.condition[0] + self.assertEqual(prop.time_aggregation, time_aggregation) + self.assertEqual(prop.metric_name, metric_name) + self.assertEqual(prop.operator, operator) + self.assertEqual(prop.threshold, threshold) + self.assertEqual(prop.metric_namespace, metric_namespace) + + def check_dimension(self, ns, index, name, operator, values): + dim = ns.condition[0].dimensions[index] + self.assertEqual(dim.name, name) + self.assertEqual(dim.operator, operator) + self.assertEqual(dim.values, values) + + def test_monitor_metric_alert_condition_action(self): + + from knack.util import CLIError + + ns = self._build_namespace() + self.call_condition(ns, 'avg ns."CPU Percent" > 90') + self.check_condition(ns, 'Average', 'ns', 'CPU Percent', 'GreaterThan', '90') + + ns = self._build_namespace() + self.call_condition(ns, 'avg ns."a.b/c_d" > 90') + self.check_condition(ns, 'Average', 'ns', 'a.b/c_d', 'GreaterThan', '90') + + ns = self._build_namespace() + self.call_condition(ns, 'avg CPU Percent > 90') + self.check_condition(ns, 'Average', None, 'CPU Percent', 'GreaterThan', '90') + + ns = self._build_namespace() + self.call_condition(ns, 'avg "a.b/c_d" > 90') + self.check_condition(ns, 'Average', None, 'a.b/c_d', 'GreaterThan', '90') + + ns = self._build_namespace() + self.call_condition(ns, 'avg SuccessE2ELatency > 250 where ApiName includes GetBlob or PutBlob') + self.check_condition(ns, 'Average', None, 'SuccessE2ELatency', 'GreaterThan', '250') + self.check_dimension(ns, 0, 'ApiName', 'includes', ['GetBlob', 'PutBlob']) + + ns = self._build_namespace() + self.call_condition(ns, 'avg ns.foo/bar_doo > 90') + self.check_condition(ns, 'Average', 'ns', 'foo/bar_doo', 'GreaterThan', '90') + + ns = self._build_namespace() + with self.assertRaisesRegexp(CLIError, 'usage error: --condition'): + self.call_condition(ns, 'avg blah"what > 90') + + ns = self._build_namespace() + with self.assertRaisesRegexp(CLIError, 'usage error: --condition'): + self.call_condition(ns, 'avg Wra!!ga * woo') diff --git a/src/command_modules/azure-cli-monitor/setup.py b/src/command_modules/azure-cli-monitor/setup.py index 69a335967d2..2df00b9a5fd 100644 --- a/src/command_modules/azure-cli-monitor/setup.py +++ b/src/command_modules/azure-cli-monitor/setup.py @@ -12,7 +12,7 @@ logger.warn("Wheel is not available, disabling bdist_wheel hook") cmdclass = {} -VERSION = "0.2.5" +VERSION = "0.2.6" CLASSIFIERS = [ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers',