Hello community, here is the log from the commit of package azure-cli-core for openSUSE:Factory checked in at 2020-10-13 15:44:31 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/azure-cli-core (Old) and /work/SRC/openSUSE:Factory/.azure-cli-core.new.3486 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "azure-cli-core" Tue Oct 13 15:44:31 2020 rev:19 rq:841540 version:2.13.0 Changes: -------- --- /work/SRC/openSUSE:Factory/azure-cli-core/azure-cli-core.changes 2020-10-02 17:32:48.394577620 +0200 +++ /work/SRC/openSUSE:Factory/.azure-cli-core.new.3486/azure-cli-core.changes 2020-10-13 15:45:50.209454658 +0200 @@ -1,0 +2,9 @@ +Tue Oct 13 09:35:54 UTC 2020 - John Paul Adrian Glaubitz <adrian.glaub...@suse.com> + +- New upstream release + + Version 2.13.0 + + For detailed information about changes see the + HISTORY.rst file provided with this package +- Override upstream version in Requires for python-azure-mgmt-resource + +------------------------------------------------------------------- Old: ---- azure-cli-core-2.12.1.tar.gz New: ---- azure-cli-core-2.13.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ azure-cli-core.spec ++++++ --- /var/tmp/diff_new_pack.qHx9Ua/_old 2020-10-13 15:45:50.941454974 +0200 +++ /var/tmp/diff_new_pack.qHx9Ua/_new 2020-10-13 15:45:50.941454974 +0200 @@ -17,7 +17,7 @@ Name: azure-cli-core -Version: 2.12.1 +Version: 2.13.0 Release: 0 Summary: Microsoft Azure CLI Core Module License: MIT @@ -43,8 +43,8 @@ Requires: python3-argcomplete >= 1.8 Requires: python3-azure-mgmt-core < 2.0.0 Requires: python3-azure-mgmt-core >= 1.2.0 -Requires: python3-azure-mgmt-resource < 11.0.0 -Requires: python3-azure-mgmt-resource >= 10.2.0 +Requires: python3-azure-mgmt-resource < 16.0.0 +Requires: python3-azure-mgmt-resource >= 15.0.0 Requires: python3-azure-nspkg >= 3.0.0 Requires: python3-colorama >= 0.4.1 Requires: python3-humanfriendly < 9.0 ++++++ azure-cli-core-2.12.1.tar.gz -> azure-cli-core-2.13.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.12.1/HISTORY.rst new/azure-cli-core-2.13.0/HISTORY.rst --- old/azure-cli-core-2.12.1/HISTORY.rst 2020-09-28 10:37:30.000000000 +0200 +++ new/azure-cli-core-2.13.0/HISTORY.rst 2020-10-12 09:58:16.000000000 +0200 @@ -3,6 +3,10 @@ Release History =============== +2.13.0 +++++++ +* Minor fixes + 2.12.1 ++++++ * No changes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.12.1/PKG-INFO new/azure-cli-core-2.13.0/PKG-INFO --- old/azure-cli-core-2.12.1/PKG-INFO 2020-09-28 10:37:45.000000000 +0200 +++ new/azure-cli-core-2.13.0/PKG-INFO 2020-10-12 09:58:34.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: azure-cli-core -Version: 2.12.1 +Version: 2.13.0 Summary: Microsoft Azure Command-Line Tools Core Module Home-page: https://github.com/Azure/azure-cli Author: Microsoft Corporation @@ -15,6 +15,10 @@ Release History =============== + 2.13.0 + ++++++ + * Minor fixes + 2.12.1 ++++++ * No changes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.12.1/azure/cli/core/__init__.py new/azure-cli-core-2.13.0/azure/cli/core/__init__.py --- old/azure-cli-core-2.12.1/azure/cli/core/__init__.py 2020-09-28 10:37:30.000000000 +0200 +++ new/azure-cli-core-2.13.0/azure/cli/core/__init__.py 2020-10-12 09:58:16.000000000 +0200 @@ -6,7 +6,7 @@ from __future__ import print_function -__version__ = "2.12.1" +__version__ = "2.13.0" import os import sys diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.12.1/azure/cli/core/adal_authentication.py new/azure-cli-core-2.13.0/azure/cli/core/adal_authentication.py --- old/azure-cli-core-2.12.1/azure/cli/core/adal_authentication.py 2020-09-28 10:37:30.000000000 +0200 +++ new/azure-cli-core-2.13.0/azure/cli/core/adal_authentication.py 2020-10-12 09:58:16.000000000 +0200 @@ -36,7 +36,7 @@ if in_cloud_console(): AdalAuthentication._log_hostname() - err = (getattr(err, 'error_response', None) or {}).get('error_description') or '' + err = (getattr(err, 'error_response', None) or {}).get('error_description') or str(err) if 'AADSTS70008' in err: # all errors starting with 70008 should be creds expiration related raise CLIError("Credentials have expired due to inactivity. {}".format( "Please run 'az login'" if not in_cloud_console() else '')) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.12.1/azure/cli/core/azclierror.py new/azure-cli-core-2.13.0/azure/cli/core/azclierror.py --- old/azure-cli-core-2.12.1/azure/cli/core/azclierror.py 2020-09-28 10:37:30.000000000 +0200 +++ new/azure-cli-core-2.13.0/azure/cli/core/azclierror.py 2020-10-12 09:58:16.000000000 +0200 @@ -4,85 +4,209 @@ # -------------------------------------------------------------------------------------------- import sys -from enum import Enum +import azure.cli.core.telemetry as telemetry from knack.util import CLIError from knack.log import get_logger logger = get_logger(__name__) +# pylint: disable=unnecessary-pass -class AzCLIErrorType(Enum): - """ AzureCLI error types """ - - # userfaults - CommandNotFoundError = 'CommandNotFoundError' - ArgumentParseError = 'ArgumentParseError' - ValidationError = 'ValidationError' - ManualInterrupt = 'ManualInterrupt' - # service side error - ServiceError = 'ServiceError' - # client side error - ClientError = 'ClientError' - # unexpected error - UnexpectedError = 'UnexpectedError' +# Error types in AzureCLI are from different sources, and there are many general error types like CLIError, AzureError. +# Besides, many error types with different names are actually showing the same kind of error. +# For example, CloudError, CLIError and ValidtionError all could be a resource-not-found error. +# Therefore, here we define the new error classes to map and categorize all of the error types from different sources. +# region: Base Layer +# Base class for all the AzureCLI defined error classes. +# DO NOT raise the error class here directly in your codes. class AzCLIError(CLIError): - """ AzureCLI error definition """ + """ Base class for all the AzureCLI defined error classes. """ - def __init__(self, error_type, error_msg, raw_exception=None, command=None): - """ - :param error_type: The name of the AzureCLI error type. - :type error_type: azure.cli.core.util.AzCLIErrorType - :param error_msg: The error message detail. - :type error_msg: str - :param raw_exception: The raw exception. - :type raw_exception: Exception - :param command: The command which brings the error. - :type command: str - :param recommendations: The recommendations to resolve the error. - :type recommendations: list - """ - self.error_type = error_type + def __init__(self, error_msg, recommendation=None): + # error message self.error_msg = error_msg - self.raw_exception = raw_exception - self.command = command + + # set recommendations to fix the error if the message is not actionable, + # they will be printed to users after the error message, one recommendation per line self.recommendations = [] + if isinstance(recommendation, str): + self.recommendations = [recommendation] + elif isinstance(recommendation, list): + self.recommendations = recommendation + + # exception trace for the error + self.exception_trace = None super().__init__(error_msg) def set_recommendation(self, recommendation): self.recommendations.append(recommendation) - def set_raw_exception(self, raw_exception): - self.raw_exception = raw_exception + def set_exception_trace(self, exception_trace): + self.exception_trace = exception_trace def print_error(self): from azure.cli.core.azlogging import CommandLoggerContext with CommandLoggerContext(logger): - message = '{}: {}'.format(self.error_type.value, self.error_msg) + # print error type and error message + message = '{}: {}'.format(self.__class__.__name__, self.error_msg) logger.error(message) - if self.raw_exception: - logger.exception(self.raw_exception) + # print exception trace if there is + if self.exception_trace: + logger.exception(self.exception_trace) + # print recommendations to action if self.recommendations: for recommendation in self.recommendations: print(recommendation, file=sys.stderr) def send_telemetry(self): - import azure.cli.core.telemetry as telemetry - telemetry.set_error_type(self.error_type.value) + telemetry.set_error_type(self.__class__.__name__) +# endregion + + +# region: Second Layer +# Main categories of the AzureCLI error types, used for Telemetry analysis +# DO NOT raise the error classes here directly in your codes. +class UserFault(AzCLIError): + """ Users should be responsible for the errors. """ + def send_telemetry(self): + super().send_telemetry() + telemetry.set_user_fault(self.error_msg) + + +class ServiceError(AzCLIError): + """ Azure Services should be responsible for the errors. """ + def send_telemetry(self): + super().send_telemetry() + telemetry.set_failure(self.error_msg) + + +class ClientError(AzCLIError): + """ AzureCLI should be responsible for the errors. """ + def send_telemetry(self): + super().send_telemetry() + telemetry.set_failure(self.error_msg) + if self.exception_trace: + telemetry.set_exception(self.exception_trace, '') +# endregion + + +# region: Third Layer +# Sub-categories of the AzureCLI error types, shown to users +# Raise the error classes here in your codes +# Avoid using fallback error classes unless you can not find a proper one +# Command related error types +class CommandNotFoundError(UserFault): + """ Command is misspelled or not recognized by AzureCLI. """ + pass + + +# Argument related error types +class UnrecognizedArgumentError(UserFault): + """ Argument is misspelled or not recognized by AzureCLI. """ + pass + + +class RequiredArgumentMissingError(UserFault): + """ Required argument is not specified. """ + pass + + +class MutuallyExclusiveArgumentError(UserFault): + """ Arguments can not be specfied together. """ + pass + + +class InvalidArgumentValueError(UserFault): + """ Argument value is not valid. """ + pass + + +class ArgumentParseError(UserFault): + """ Fallback of the argument parsing related errors. + Avoid using this class unless the error can not be classified + into the above Argument related error types. """ + pass + + +# Response related error types +class BadRequestError(UserFault): + """ Bad request from client: 400 error """ + pass + + +class UnauthorizedError(UserFault): + """ Unauthorized request: 401 error """ + + +class ForbiddenError(UserFault): + """ Service refuse to response: 403 error """ + + +class ResourceNotFoundError(UserFault): + """ Can not find Azure resources: 404 error """ + pass + + +class AzureInternalError(ServiceError): + """ Azure service internal error: 5xx error """ + pass + + +class AzureResponseError(UserFault): + """ Fallback of the response related errors. + Avoid using this class unless the error can not be classified + into the above Response related error types. """ + + +# Request related error types +class AzureConnectionError(UserFault): + """ Connection issues like connection timeout, aborted or broken. """ + pass + + +class ClientRequestError(UserFault): + """ Fallback of the request related errors. Error occurs while attempting + to make a request to the service. No request is sent. + Avoid using this class unless the error can not be classified + into the above Request related errors types. """ + + +# Validation related error types +class ValidationError(UserFault): + """ Fallback of the errors in validation functions. + Avoid using this class unless the error can not be classified into + the Argument, Request and Response related error types above. """ + pass + + +# CLI internal error type +class CLIInternalError(ClientError): + """ AzureCLI internal error """ + pass + + +# Keyboard interrupt error type +class ManualInterrupt(UserFault): + """ Keyboard interrupt. """ + pass + + +# Unknow error type +class UnknownError(UserFault): + """ Reserved for the errors which can not be categorized into the error types above. + Usually for the very general error type like CLIError, AzureError. + Error type info will not printed to users for this class. """ + def print_error(self): + from azure.cli.core.azlogging import CommandLoggerContext + with CommandLoggerContext(logger): + # print only error message (no error type) + logger.error(self.error_msg) + # print recommendations to action + if self.recommendations: + for recommendation in self.recommendations: + print(recommendation, file=sys.stderr) - # For userfaults - if self.error_type in [AzCLIErrorType.CommandNotFoundError, - AzCLIErrorType.ArgumentParseError, - AzCLIErrorType.ValidationError, - AzCLIErrorType.ManualInterrupt]: - telemetry.set_user_fault(self.error_msg) - - # For failures: service side error, client side error, unexpected error - else: - telemetry.set_failure(self.error_msg) - - # For unexpected error - if self.raw_exception: - telemetry.set_exception(self.raw_exception, '') +# endregion diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.12.1/azure/cli/core/cloud.py new/azure-cli-core-2.13.0/azure/cli/core/cloud.py --- old/azure-cli-core-2.12.1/azure/cli/core/cloud.py 2020-09-28 10:37:30.000000000 +0200 +++ new/azure-cli-core-2.13.0/azure/cli/core/cloud.py 2020-10-12 09:58:16.000000000 +0200 @@ -78,6 +78,7 @@ app_insights_telemetry_channel_resource_id=None, synapse_analytics_resource_id=None, attestation_resource_id=None, + portal=None, **kwargs): # To support init with __dict__ for deserialization # Attribute names are significant. They are used when storing/retrieving clouds from config self.management = management @@ -98,6 +99,7 @@ self.app_insights_telemetry_channel_resource_id = app_insights_telemetry_channel_resource_id self.synapse_analytics_resource_id = synapse_analytics_resource_id self.attestation_resource_id = attestation_resource_id + self.portal = portal def has_endpoint_set(self, endpoint_name): try: @@ -309,7 +311,8 @@ log_analytics_resource_id=get_endpoint('logAnalyticsResourceId', fallback_value=_get_log_analytics_resource_id(arm_dict['name'])), synapse_analytics_resource_id=get_endpoint('synapseAnalyticsResourceId', fallback_value=_get_synapse_analytics_resource_id(arm_dict['name'])), app_insights_telemetry_channel_resource_id=get_endpoint('appInsightsTelemetryChannelResourceId', fallback_value=_get_app_insights_telemetry_channel_resource_id(arm_dict['name'])), - attestation_resource_id=get_endpoint('attestationResourceId', fallback_value=_get_attestation_resource_id(arm_dict['name']))), + attestation_resource_id=get_endpoint('attestationResourceId', fallback_value=_get_attestation_resource_id(arm_dict['name'])), + portal=arm_dict['portal'] if 'portal' in arm_dict else None), suffixes=CloudSuffixes( storage_endpoint=get_suffix('storage'), storage_sync_endpoint=get_suffix('storageSyncEndpointSuffix', fallback_value=_get_storage_sync_endpoint(arm_dict['name'])), @@ -381,7 +384,8 @@ log_analytics_resource_id='https://api.loganalytics.io', app_insights_telemetry_channel_resource_id='https://dc.applicationinsights.azure.com/v2/track', synapse_analytics_resource_id='https://dev.azuresynapse.net', - attestation_resource_id='https://attest.azure.net'), + attestation_resource_id='https://attest.azure.net', + portal='https://portal.azure.com'), suffixes=CloudSuffixes( storage_endpoint='core.windows.net', storage_sync_endpoint='afs.azure.net', @@ -415,7 +419,8 @@ app_insights_resource_id='https://api.applicationinsights.azure.cn', log_analytics_resource_id='https://api.loganalytics.azure.cn', app_insights_telemetry_channel_resource_id='https://dc.applicationinsights.azure.cn/v2/track', - synapse_analytics_resource_id='https://dev.azuresynapse.net'), + synapse_analytics_resource_id='https://dev.azuresynapse.net', + portal='https://portal.azure.cn'), suffixes=CloudSuffixes( storage_endpoint='core.chinacloudapi.cn', keyvault_dns='.vault.azure.cn', @@ -444,7 +449,8 @@ ossrdbms_resource_id='https://ossrdbms-aad.database.usgovcloudapi.net', app_insights_resource_id='https://api.applicationinsights.us', log_analytics_resource_id='https://api.loganalytics.us', - app_insights_telemetry_channel_resource_id='https://dc.applicationinsights.us/v2/track'), + app_insights_telemetry_channel_resource_id='https://dc.applicationinsights.us/v2/track', + portal='https://portal.azure.us'), suffixes=CloudSuffixes( storage_endpoint='core.usgovcloudapi.net', storage_sync_endpoint='afs.azure.us', @@ -470,7 +476,8 @@ microsoft_graph_resource_id='https://graph.microsoft.de', vm_image_alias_doc='https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/arm-compute/quickstart-templates/aliases.json', media_resource_id='https://rest.media.cloudapi.de', - ossrdbms_resource_id='https://ossrdbms-aad.database.cloudapi.de'), + ossrdbms_resource_id='https://ossrdbms-aad.database.cloudapi.de', + portal='https://portal.microsoftazure.de'), suffixes=CloudSuffixes( storage_endpoint='core.cloudapi.de', keyvault_dns='.vault.microsoftazure.de', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.12.1/azure/cli/core/command_recommender.py new/azure-cli-core-2.13.0/azure/cli/core/command_recommender.py --- old/azure-cli-core-2.12.1/azure/cli/core/command_recommender.py 2020-09-28 10:37:30.000000000 +0200 +++ new/azure-cli-core-2.13.0/azure/cli/core/command_recommender.py 2020-10-12 09:58:16.000000000 +0200 @@ -118,9 +118,11 @@ }, headers=headers, timeout=1) + telemetry.set_debug_info('AladdinResponseTime', response.elapsed.total_seconds()) + except RequestException as ex: logger.debug('Recommendation requests.get() exception: %s', ex) - telemetry.set_debug_info('AladdinRecommendationService', ex.__class__.__name__) + telemetry.set_debug_info('AladdinException', ex.__class__.__name__) recommendations = [] if response and response.status_code == HTTPStatus.OK: @@ -174,8 +176,19 @@ elif self.aladdin_recommendations: recommend_command = self.aladdin_recommendations[0] + # set the recommened command into Telemetry + self._set_recommended_command_to_telemetry(recommend_command) + return recommend_command + def _set_recommended_command_to_telemetry(self, recommend_command): + """Set the recommended command to Telemetry for analysis. """ + + if recommend_command in self.aladdin_recommendations: + telemetry.set_debug_info('AladdinRecommendCommand', recommend_command) + elif recommend_command: + telemetry.set_debug_info('ExampleRecommendCommand', recommend_command) + def _disable_aladdin_service(self): """Decide whether to disable aladdin request when a command fails. The possible cases to disable it are: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.12.1/azure/cli/core/commands/__init__.py new/azure-cli-core-2.13.0/azure/cli/core/commands/__init__.py --- old/azure-cli-core-2.12.1/azure/cli/core/commands/__init__.py 2020-09-28 10:37:30.000000000 +0200 +++ new/azure-cli-core-2.13.0/azure/cli/core/commands/__init__.py 2020-10-12 09:58:16.000000000 +0200 @@ -845,7 +845,6 @@ pass def _validate_arg_level(self, ns, **_): # pylint: disable=no-self-use - from azure.cli.core.azclierror import AzCLIErrorType from azure.cli.core.azclierror import AzCLIError for validator in getattr(ns, '_argument_validators', []): try: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.12.1/azure/cli/core/commands/arm.py new/azure-cli-core-2.13.0/azure/cli/core/commands/arm.py --- old/azure-cli-core-2.12.1/azure/cli/core/commands/arm.py 2020-09-28 10:37:30.000000000 +0200 +++ new/azure-cli-core-2.13.0/azure/cli/core/commands/arm.py 2020-10-12 09:58:16.000000000 +0200 @@ -762,10 +762,9 @@ if getattr(getattr(ex, 'response', ex), 'status_code', None) == 404: import sys from azure.cli.core.azlogging import CommandLoggerContext - from azure.cli.core.azclierror import AzCLIErrorType - from azure.cli.core.azclierror import AzCLIError + from azure.cli.core.azclierror import ResourceNotFoundError with CommandLoggerContext(logger): - az_error = AzCLIError(AzCLIErrorType.ValidationError, getattr(ex, 'message', ex)) + az_error = ResourceNotFoundError(getattr(ex, 'message', ex)) az_error.print_error() az_error.send_telemetry() sys.exit(3) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.12.1/azure/cli/core/parser.py new/azure-cli-core-2.13.0/azure/cli/core/parser.py --- old/azure-cli-core-2.12.1/azure/cli/core/parser.py 2020-09-28 10:37:30.000000000 +0200 +++ new/azure-cli-core-2.13.0/azure/cli/core/parser.py 2020-10-12 09:58:16.000000000 +0200 @@ -17,9 +17,13 @@ from azure.cli.core.commands import ExtensionCommandSource from azure.cli.core.commands import AzCliCommandInvoker from azure.cli.core.commands.events import EVENT_INVOKER_ON_TAB_COMPLETION -from azure.cli.core.azclierror import AzCLIErrorType -from azure.cli.core.azclierror import AzCLIError from azure.cli.core.command_recommender import CommandRecommender +from azure.cli.core.azclierror import UnrecognizedArgumentError +from azure.cli.core.azclierror import RequiredArgumentMissingError +from azure.cli.core.azclierror import InvalidArgumentValueError +from azure.cli.core.azclierror import ArgumentParseError +from azure.cli.core.azclierror import CommandNotFoundError +from azure.cli.core.azclierror import ValidationError from knack.log import get_logger from knack.parser import CLICommandParser @@ -155,7 +159,7 @@ _parser=command_parser) def validation_error(self, message): - az_error = AzCLIError(AzCLIErrorType.ValidationError, message, command=self.prog) + az_error = ValidationError(message) az_error.print_error() az_error.send_telemetry() self.exit(2) @@ -168,7 +172,14 @@ recommender.set_help_examples(self.get_examples(self.prog)) recommendation = recommender.recommend_a_command() - az_error = AzCLIError(AzCLIErrorType.ArgumentParseError, message, command=self.prog) + az_error = ArgumentParseError(message) + if 'unrecognized arguments' in message: + az_error = UnrecognizedArgumentError(message) + elif 'arguments are required' in message: + az_error = RequiredArgumentMissingError(message) + elif 'invalid' in message: + az_error = InvalidArgumentValueError(message) + if '--query' in message: from azure.cli.core.util import QUERY_REFERENCE az_error.set_recommendation(QUERY_REFERENCE) @@ -457,7 +468,7 @@ if not error_msg: # parser has no `command_source`, value is part of command itself error_msg = "'{value}' is misspelled or not recognized by the system.".format(value=value) - az_error = AzCLIError(AzCLIErrorType.CommandNotFoundError, error_msg, command=self.prog) + az_error = CommandNotFoundError(error_msg) else: # `command_source` indicates command values have been parsed, value is an argument @@ -465,7 +476,7 @@ error_msg = "{prog}: '{value}' is not a valid value for '{param}'.".format( prog=self.prog, value=value, param=parameter) candidates = difflib.get_close_matches(value, action.choices, cutoff=0.7) - az_error = AzCLIError(AzCLIErrorType.ArgumentParseError, error_msg, command=self.prog) + az_error = InvalidArgumentValueError(error_msg) command_arguments = self._get_failure_recovery_arguments(action) if candidates: @@ -479,7 +490,7 @@ az_error.set_recommendation("Try this: '{}'".format(recommended_command)) # remind user to check extensions if we can not find a command to recommend - if az_error.error_type == AzCLIErrorType.CommandNotFoundError \ + if isinstance(az_error, CommandNotFoundError) \ and not az_error.recommendations and self.prog == 'az' \ and use_dynamic_install == 'no': az_error.set_recommendation(EXTENSION_REFERENCE) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.12.1/azure/cli/core/profiles/_shared.py new/azure-cli-core-2.13.0/azure/cli/core/profiles/_shared.py --- old/azure-cli-core-2.12.1/azure/cli/core/profiles/_shared.py 2020-09-28 10:37:30.000000000 +0200 +++ new/azure-cli-core-2.13.0/azure/cli/core/profiles/_shared.py 2020-10-12 09:58:16.000000000 +0200 @@ -48,6 +48,7 @@ MGMT_RESOURCE_RESOURCES = ('azure.mgmt.resource.resources', 'ResourceManagementClient') MGMT_RESOURCE_SUBSCRIPTIONS = ('azure.mgmt.resource.subscriptions', 'SubscriptionClient') MGMT_RESOURCE_DEPLOYMENTSCRIPTS = ('azure.mgmt.resource.deploymentscripts', 'DeploymentScriptsClient') + MGMT_RESOURCE_TEMPLATESPECS = ('azure.mgmt.resource.templatespecs', 'TemplateSpecsClient') MGMT_MONITOR = ('azure.mgmt.monitor', 'MonitorManagementClient') DATA_KEYVAULT = ('azure.keyvault', 'KeyVaultClient') DATA_PRIVATE_KEYVAULT = ('azure.cli.command_modules.keyvault.vendored_sdks.azure_keyvault_t1', 'KeyVaultClient') @@ -153,6 +154,7 @@ ResourceType.MGMT_RESOURCE_RESOURCES: '2020-06-01', ResourceType.MGMT_RESOURCE_SUBSCRIPTIONS: '2019-11-01', ResourceType.MGMT_RESOURCE_DEPLOYMENTSCRIPTS: '2019-10-01-preview', + ResourceType.MGMT_RESOURCE_TEMPLATESPECS: '2019-06-01-preview', ResourceType.MGMT_NETWORK_DNS: '2018-05-01', ResourceType.MGMT_KEYVAULT: '2020-04-01-preview', ResourceType.MGMT_AUTHORIZATION: SDKProfile('2020-04-01-preview', { @@ -221,6 +223,7 @@ ResourceType.MGMT_RESOURCE_POLICY: '2016-12-01', ResourceType.MGMT_RESOURCE_RESOURCES: '2018-05-01', ResourceType.MGMT_RESOURCE_SUBSCRIPTIONS: '2016-06-01', + ResourceType.MGMT_RESOURCE_TEMPLATESPECS: '2015-01-01', ResourceType.MGMT_NETWORK_DNS: '2016-04-01', ResourceType.MGMT_KEYVAULT: '2016-10-01', ResourceType.MGMT_AUTHORIZATION: SDKProfile('2015-07-01', { @@ -251,6 +254,7 @@ ResourceType.MGMT_RESOURCE_POLICY: '2016-12-01', ResourceType.MGMT_RESOURCE_RESOURCES: '2018-02-01', ResourceType.MGMT_RESOURCE_SUBSCRIPTIONS: '2016-06-01', + ResourceType.MGMT_RESOURCE_TEMPLATESPECS: '2015-01-01', ResourceType.MGMT_NETWORK_DNS: '2016-04-01', ResourceType.MGMT_KEYVAULT: '2016-10-01', ResourceType.MGMT_AUTHORIZATION: SDKProfile('2015-07-01', { @@ -273,6 +277,7 @@ ResourceType.MGMT_RESOURCE_POLICY: '2015-10-01-preview', ResourceType.MGMT_RESOURCE_RESOURCES: '2016-02-01', ResourceType.MGMT_RESOURCE_SUBSCRIPTIONS: '2016-06-01', + ResourceType.MGMT_RESOURCE_TEMPLATESPECS: '2015-01-01', ResourceType.MGMT_NETWORK_DNS: '2016-04-01', ResourceType.MGMT_KEYVAULT: '2016-10-01', ResourceType.MGMT_AUTHORIZATION: SDKProfile('2015-07-01', { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.12.1/azure/cli/core/telemetry.py new/azure-cli-core-2.13.0/azure/cli/core/telemetry.py --- old/azure-cli-core-2.12.1/azure/cli/core/telemetry.py 2020-09-28 10:37:30.000000000 +0200 +++ new/azure-cli-core-2.13.0/azure/cli/core/telemetry.py 2020-10-12 09:58:16.000000000 +0200 @@ -45,7 +45,7 @@ self.extension_management_detail = None self.raw_command = None self.mode = 'default' - # The AzCLIErrorType + # The AzCLIError sub-class name self.error_type = 'None' # The class name of the raw exception self.exception_name = 'None' @@ -453,7 +453,11 @@ # of these sub-processes will be very close, usually in several milliseconds. We use 1 second as the threshold here. # When the difference of create time between current process and its parent process is larger than the threshold, # the parent process will be viewed as the terminal process. - import psutil + try: + # psutil is not available on cygwin + import psutil + except ImportError: + return "" time_threshold = 1 process = psutil.Process() while process and process.ppid() and process.pid != process.ppid(): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.12.1/azure/cli/core/util.py new/azure-cli-core-2.13.0/azure/cli/core/util.py --- old/azure-cli-core-2.12.1/azure/cli/core/util.py 2020-09-28 10:37:30.000000000 +0200 +++ new/azure-cli-core-2.13.0/azure/cli/core/util.py 2020-10-12 09:58:16.000000000 +0200 @@ -17,8 +17,6 @@ import six from six.moves.urllib.request import urlopen # pylint: disable=import-error -from azure.cli.core.azclierror import AzCLIErrorType -from azure.cli.core.azclierror import AzCLIError from knack.log import get_logger from knack.util import CLIError, to_snake_case @@ -55,7 +53,7 @@ ] -def handle_exception(ex): # pylint: disable=too-many-return-statements, too-many-statements +def handle_exception(ex): # pylint: disable=too-many-locals, too-many-statements, too-many-branches # For error code, follow guidelines at https://docs.python.org/2/library/sys.html#sys.exit, from jmespath.exceptions import JMESPathTypeError from msrestazure.azure_exceptions import CloudError @@ -64,6 +62,7 @@ from azure.common import AzureException from azure.core.exceptions import AzureError from requests.exceptions import SSLError + import azure.cli.core.azclierror as azclierror import traceback logger.debug("azure.cli.core.util.handle_exception is called with an exception:") @@ -74,78 +73,156 @@ error_msg = getattr(ex, 'message', str(ex)) exit_code = 1 - if isinstance(ex, AzCLIError): + if isinstance(ex, azclierror.AzCLIError): az_error = ex elif isinstance(ex, JMESPathTypeError): error_msg = "Invalid jmespath query supplied for `--query`: {}".format(error_msg) - az_error = AzCLIError(AzCLIErrorType.ArgumentParseError, error_msg) + az_error = azclierror.InvalidArgumentValueError(error_msg) az_error.set_recommendation(QUERY_REFERENCE) + elif isinstance(ex, SSLError): + az_error = azclierror.AzureConnectionError(error_msg) + az_error.set_recommendation(SSLERROR_TEMPLATE) + + elif isinstance(ex, CloudError): + if extract_common_error_message(ex): + error_msg = extract_common_error_message(ex) + status_code = str(getattr(ex, 'status_code', 'Unknown Code')) + AzCLIErrorType = get_error_type_by_status_code(status_code) + az_error = AzCLIErrorType(error_msg) + elif isinstance(ex, ValidationError): - az_error = AzCLIError(AzCLIErrorType.ValidationError, error_msg) + az_error = azclierror.ValidationError(error_msg) - # TODO: Fine-grained analysis to decide whether they are ValidationErrors - elif isinstance(ex, (CLIError, CloudError, AzureError)): - try: - error_msg = ex.args[0] - for detail in ex.args[0].error.details: - error_msg += ('\n' + detail) - except Exception: # pylint: disable=broad-except - pass - az_error = AzCLIError(AzCLIErrorType.ValidationError, error_msg) - exit_code = ex.args[1] if len(ex.args) >= 2 else 1 + elif isinstance(ex, CLIError): + # TODO: Fine-grained analysis here for Unknown error + az_error = azclierror.UnknownError(error_msg) + + elif isinstance(ex, AzureError): + if extract_common_error_message(ex): + error_msg = extract_common_error_message(ex) + AzCLIErrorType = get_error_type_by_azure_error(ex) + az_error = AzCLIErrorType(error_msg) - # TODO: Fine-grained analysis elif isinstance(ex, AzureException): - az_error = AzCLIError(AzCLIErrorType.ServiceError, error_msg) - exit_code = ex.args[1] if len(ex.args) >= 2 else 1 - - # TODO: Fine-grained analysis - elif isinstance(ex, (ClientRequestError, SSLError)): - az_error = AzCLIError(AzCLIErrorType.ClientError, error_msg) - if 'SSLError' in error_msg: - az_error.set_recommendation(SSLERROR_TEMPLATE) + if is_azure_connection_error(error_msg): + az_error = azclierror.AzureConnectionError(error_msg) + else: + # TODO: Fine-grained analysis here for Unknown error + az_error = azclierror.UnknownError(error_msg) + + elif isinstance(ex, ClientRequestError): + if is_azure_connection_error(error_msg): + az_error = azclierror.AzureConnectionError(error_msg) + else: + az_error = azclierror.ClientRequestError(error_msg) - # TODO: Fine-grained analysis elif isinstance(ex, HttpOperationError): - try: - response = json.loads(ex.response.text) - if isinstance(response, str): - error = response - else: - error = response['error'] - - # ARM should use ODATA v4. So should try this first. - # http://docs.oasis-open.org/odata/odata-json-format/v4.0/os/odata-json-format-v4.0-os.html#_Toc372793091 - if isinstance(error, dict): - code = "{} - ".format(error.get('code', 'Unknown Code')) - message = error.get('message', ex) - error_msg = "code: {}, {}".format(code, message) - else: - error_msg = error - - except (ValueError, KeyError): - pass - - az_error = AzCLIError(AzCLIErrorType.ServiceError, error_msg) + message, status_code = extract_http_operation_error(ex) + if message: + error_msg = message + AzCLIErrorType = get_error_type_by_status_code(status_code) + az_error = AzCLIErrorType(error_msg) elif isinstance(ex, KeyboardInterrupt): error_msg = 'Keyboard interrupt is captured.' - az_error = AzCLIError(AzCLIErrorType.ManualInterrupt, error_msg) + az_error = azclierror.ManualInterrupt(error_msg) else: error_msg = "The command failed with an unexpected error. Here is the traceback:" - az_error = AzCLIError(AzCLIErrorType.UnexpectedError, error_msg) - az_error.set_raw_exception(ex) + az_error = azclierror.CLIInternalError(error_msg) + az_error.set_exception_trace(ex) az_error.set_recommendation("To open an issue, please run: 'az feedback'") + if isinstance(az_error, azclierror.ResourceNotFoundError): + exit_code = 3 + az_error.print_error() az_error.send_telemetry() return exit_code +def extract_common_error_message(ex): + error_msg = None + try: + error_msg = ex.args[0] + for detail in ex.args[0].error.details: + error_msg += ('\n' + detail) + except Exception: # pylint: disable=broad-except + pass + return error_msg + + +def extract_http_operation_error(ex): + error_msg = None + status_code = 'Unknown Code' + try: + response = json.loads(ex.response.text) + if isinstance(response, str): + error = response + else: + error = response['error'] + # ARM should use ODATA v4. So should try this first. + # http://docs.oasis-open.org/odata/odata-json-format/v4.0/os/odata-json-format-v4.0-os.html#_Toc372793091 + if isinstance(error, dict): + status_code = error.get('code', 'Unknown Code') + code_str = "{} - ".format(status_code) + message = error.get('message', ex) + error_msg = "code: {}, {}".format(code_str, message) + else: + error_msg = error + except (ValueError, KeyError): + pass + return error_msg, status_code + + +def get_error_type_by_azure_error(ex): + import azure.core.exceptions as exceptions + import azure.cli.core.azclierror as azclierror + + if isinstance(ex, exceptions.HttpResponseError): + status_code = str(ex.status_code) + return get_error_type_by_status_code(status_code) + if isinstance(ex, exceptions.ResourceNotFoundError): + return azclierror.ResourceNotFoundError + if isinstance(ex, exceptions.ServiceRequestError): + return azclierror.ClientRequestError + if isinstance(ex, exceptions.ServiceRequestTimeoutError): + return azclierror.AzureConnectionError + if isinstance(ex, (exceptions.ServiceResponseError, exceptions.ServiceResponseTimeoutError)): + return azclierror.AzureResponseError + + return azclierror.UnknownError + + +def get_error_type_by_status_code(status_code): + import azure.cli.core.azclierror as azclierror + + if status_code == '400': + return azclierror.BadRequestError + if status_code == '401': + return azclierror.UnauthorizedError + if status_code == '403': + return azclierror.ForbiddenError + if status_code == '404': + return azclierror.ResourceNotFoundError + if status_code.startswith('5'): + return azclierror.AzureInternalError + + return azclierror.AzureResponseError + + +def is_azure_connection_error(error_msg): + error_msg = error_msg.lower() + if 'connection error' in error_msg \ + or 'connection broken' in error_msg \ + or 'connection aborted' in error_msg: + return True + return False + + # pylint: disable=inconsistent-return-statements def empty_on_404(ex): from msrestazure.azure_exceptions import CloudError diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.12.1/azure_cli_core.egg-info/PKG-INFO new/azure-cli-core-2.13.0/azure_cli_core.egg-info/PKG-INFO --- old/azure-cli-core-2.12.1/azure_cli_core.egg-info/PKG-INFO 2020-09-28 10:37:45.000000000 +0200 +++ new/azure-cli-core-2.13.0/azure_cli_core.egg-info/PKG-INFO 2020-10-12 09:58:34.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: azure-cli-core -Version: 2.12.1 +Version: 2.13.0 Summary: Microsoft Azure Command-Line Tools Core Module Home-page: https://github.com/Azure/azure-cli Author: Microsoft Corporation @@ -15,6 +15,10 @@ Release History =============== + 2.13.0 + ++++++ + * Minor fixes + 2.12.1 ++++++ * No changes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.12.1/setup.py new/azure-cli-core-2.13.0/setup.py --- old/azure-cli-core-2.12.1/setup.py 2020-09-28 10:37:30.000000000 +0200 +++ new/azure-cli-core-2.13.0/setup.py 2020-10-12 09:58:16.000000000 +0200 @@ -9,7 +9,7 @@ from codecs import open from setuptools import setup -VERSION = "2.12.1" +VERSION = "2.13.0" # If we have source, validate that our version numbers match # This should prevent uploading releases with mismatched versions.