Hello community, here is the log from the commit of package azure-cli-core for openSUSE:Factory checked in at 2020-12-04 21:28:23 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/azure-cli-core (Old) and /work/SRC/openSUSE:Factory/.azure-cli-core.new.5913 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "azure-cli-core" Fri Dec 4 21:28:23 2020 rev:21 rq:851831 version:2.15.0 Changes: -------- --- /work/SRC/openSUSE:Factory/azure-cli-core/azure-cli-core.changes 2020-11-17 21:25:46.157406606 +0100 +++ /work/SRC/openSUSE:Factory/.azure-cli-core.new.5913/azure-cli-core.changes 2020-12-04 21:28:24.526118011 +0100 @@ -1,0 +2,9 @@ +Wed Nov 18 11:55:02 UTC 2020 - John Paul Adrian Glaubitz <adrian.glaub...@suse.com> + +- New upstream release + + Version 2.15.0 + + For detailed information about changes see the + HISTORY.rst file provided with this package +- Update Requires from setup.py + +------------------------------------------------------------------- Old: ---- azure-cli-core-2.14.2.tar.gz New: ---- azure-cli-core-2.15.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ azure-cli-core.spec ++++++ --- /var/tmp/diff_new_pack.IHpf33/_old 2020-12-04 21:28:24.974118654 +0100 +++ /var/tmp/diff_new_pack.IHpf33/_new 2020-12-04 21:28:24.974118654 +0100 @@ -17,7 +17,7 @@ Name: azure-cli-core -Version: 2.14.2 +Version: 2.15.0 Release: 0 Summary: Microsoft Azure CLI Core Module License: MIT @@ -42,7 +42,7 @@ Requires: python3-argcomplete < 2.0 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-core >= 1.2.1 Requires: python3-azure-mgmt-resource < 16.0.0 Requires: python3-azure-mgmt-resource >= 15.0.0 Requires: python3-azure-nspkg >= 3.0.0 ++++++ azure-cli-core-2.14.2.tar.gz -> azure-cli-core-2.15.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.14.2/HISTORY.rst new/azure-cli-core-2.15.0/HISTORY.rst --- old/azure-cli-core-2.14.2/HISTORY.rst 2020-11-09 06:56:54.000000000 +0100 +++ new/azure-cli-core-2.15.0/HISTORY.rst 2020-11-13 09:42:05.000000000 +0100 @@ -3,6 +3,10 @@ Release History =============== +2.15.0 +++++++ +* Upgrade azure-mgmt-core to 1.2.1 (#15780) + 2.14.2 ++++++ * No changes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.14.2/PKG-INFO new/azure-cli-core-2.15.0/PKG-INFO --- old/azure-cli-core-2.14.2/PKG-INFO 2020-11-09 06:57:09.000000000 +0100 +++ new/azure-cli-core-2.15.0/PKG-INFO 2020-11-13 09:42:18.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: azure-cli-core -Version: 2.14.2 +Version: 2.15.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.15.0 + ++++++ + * Upgrade azure-mgmt-core to 1.2.1 (#15780) + 2.14.2 ++++++ * No changes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.14.2/azure/cli/core/__init__.py new/azure-cli-core-2.15.0/azure/cli/core/__init__.py --- old/azure-cli-core-2.14.2/azure/cli/core/__init__.py 2020-11-09 06:56:54.000000000 +0100 +++ new/azure-cli-core-2.15.0/azure/cli/core/__init__.py 2020-11-13 09:42:05.000000000 +0100 @@ -6,7 +6,7 @@ from __future__ import print_function -__version__ = "2.14.2" +__version__ = "2.15.0" import os import sys diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.14.2/azure/cli/core/_profile.py new/azure-cli-core-2.15.0/azure/cli/core/_profile.py --- old/azure-cli-core-2.14.2/azure/cli/core/_profile.py 2020-11-09 06:56:54.000000000 +0100 +++ new/azure-cli-core-2.15.0/azure/cli/core/_profile.py 2020-11-13 09:42:05.000000000 +0100 @@ -24,7 +24,6 @@ is_windows, is_wsl from azure.cli.core.cloud import get_active_cloud, set_cloud_subscription - logger = get_logger(__name__) # Names below are used by azure-xplat-cli to persist account information into @@ -273,6 +272,15 @@ if hasattr(s, 'home_tenant_id'): subscription_dict[_HOME_TENANT_ID] = s.home_tenant_id if hasattr(s, 'managed_by_tenants'): + if s.managed_by_tenants is None: + # managedByTenants is missing from the response. This is a known service issue: + # https://github.com/Azure/azure-rest-api-specs/issues/9567 + # pylint: disable=line-too-long + raise CLIError("Invalid profile is used for cloud '{cloud_name}'. " + "To configure the cloud profile, run `az cloud set --name {cloud_name} --profile <profile>(e.g. 2019-03-01-hybrid)`. " + "For more information about using Azure CLI with Azure Stack, see " + "https://docs.microsoft.com/azure-stack/user/azure-stack-version-profiles-azurecli2" + .format(cloud_name=self.cli_ctx.cloud.name)) subscription_dict[_MANAGED_BY_TENANTS] = [{_TENANT_ID: t.tenant_id} for t in s.managed_by_tenants] consolidated.append(subscription_dict) @@ -559,26 +567,35 @@ external_tenants_info.append(sub[_TENANT_ID]) if identity_type is None: - def _retrieve_token(): + def _retrieve_token(sdk_resource=None): + # When called by + # - Track 1 SDK, use `resource` specified by CLI + # - Track 2 SDK, use `sdk_resource` specified by SDK and ignore `resource` specified by CLI + token_resource = sdk_resource or resource + logger.debug("Retrieving token from ADAL for resource %r", token_resource) + if in_cloud_console() and account[_USER_ENTITY].get(_CLOUD_SHELL_ID): - return self._get_token_from_cloud_shell(resource) + return self._get_token_from_cloud_shell(token_resource) if user_type == _USER: return self._creds_cache.retrieve_token_for_user(username_or_sp_id, - account[_TENANT_ID], resource) + account[_TENANT_ID], token_resource) use_cert_sn_issuer = account[_USER_ENTITY].get(_SERVICE_PRINCIPAL_CERT_SN_ISSUER_AUTH) - return self._creds_cache.retrieve_token_for_service_principal(username_or_sp_id, resource, + return self._creds_cache.retrieve_token_for_service_principal(username_or_sp_id, token_resource, account[_TENANT_ID], use_cert_sn_issuer) - def _retrieve_tokens_from_external_tenants(): + def _retrieve_tokens_from_external_tenants(sdk_resource=None): + token_resource = sdk_resource or resource + logger.debug("Retrieving token from ADAL for external tenants and resource %r", token_resource) + external_tokens = [] for sub_tenant_id in external_tenants_info: if user_type == _USER: external_tokens.append(self._creds_cache.retrieve_token_for_user( - username_or_sp_id, sub_tenant_id, resource)) + username_or_sp_id, sub_tenant_id, token_resource)) else: external_tokens.append(self._creds_cache.retrieve_token_for_service_principal( - username_or_sp_id, resource, sub_tenant_id, resource)) + username_or_sp_id, token_resource, sub_tenant_id, token_resource)) return external_tokens from azure.cli.core.adal_authentication import AdalAuthentication @@ -621,6 +638,8 @@ return username_or_sp_id, sp_secret, None, str(account[_TENANT_ID]) def get_raw_token(self, resource=None, subscription=None, tenant=None): + logger.debug("Profile.get_raw_token invoked with resource=%r, subscription=%r, tenant=%r", + resource, subscription, tenant) if subscription and tenant: raise CLIError("Please specify only one of subscription and tenant, not both") account = self.get_subscription(subscription) @@ -805,7 +824,11 @@ from azure.cli.core.profiles._shared import get_client_class from azure.cli.core.profiles import ResourceType, get_api_version from azure.cli.core.commands.client_factory import configure_common_settings + from azure.cli.core.azclierror import CLIInternalError client_type = get_client_class(ResourceType.MGMT_RESOURCE_SUBSCRIPTIONS) + if client_type is None: + raise CLIInternalError("Unable to get '{}' in profile '{}'" + .format(ResourceType.MGMT_RESOURCE_SUBSCRIPTIONS, cli_ctx.cloud.profile)) api_version = get_api_version(cli_ctx, ResourceType.MGMT_RESOURCE_SUBSCRIPTIONS) client = client_type(credentials, api_version=api_version, base_url=self.cli_ctx.cloud.endpoints.resource_manager) @@ -817,10 +840,13 @@ def find_from_user_account(self, username, password, tenant, resource): context = self._create_auth_context(tenant) - if password: - token_entry = context.acquire_token_with_username_password(resource, username, password, _CLIENT_ID) - else: # when refresh account, we will leverage local cached tokens - token_entry = context.acquire_token(resource, username, _CLIENT_ID) + try: + if password: + token_entry = context.acquire_token_with_username_password(resource, username, password, _CLIENT_ID) + else: # when refresh account, we will leverage local cached tokens + token_entry = context.acquire_token(resource, username, _CLIENT_ID) + except Exception as err: # pylint: disable=broad-except + _login_exception_handler(err) if not token_entry: return [] @@ -841,8 +867,11 @@ # exchange the code for the token context = self._create_auth_context(tenant) - token_entry = context.acquire_token_with_authorization_code(results['code'], results['reply_url'], - resource, _CLIENT_ID, None) + try: + token_entry = context.acquire_token_with_authorization_code(results['code'], results['reply_url'], + resource, _CLIENT_ID, None) + except Exception as err: # pylint: disable=broad-except + _login_exception_handler(err) self.user_id = token_entry[_TOKEN_ENTRY_USER_ID] logger.warning("You have logged in. Now let us find all the subscriptions to which you have access...") if tenant is None: @@ -853,7 +882,10 @@ def find_through_interactive_flow(self, tenant, resource): context = self._create_auth_context(tenant) - code = context.acquire_user_code(resource, _CLIENT_ID) + try: + code = context.acquire_user_code(resource, _CLIENT_ID) + except Exception as err: # pylint: disable=broad-except + _login_exception_handler(err) logger.warning(code['message']) token_entry = context.acquire_token_with_device_code(resource, code, _CLIENT_ID) self.user_id = token_entry[_TOKEN_ENTRY_USER_ID] @@ -1261,6 +1293,12 @@ results['no_browser'] = True return + # Emit a warning to inform that a browser is opened. + # Only show the path part of the URL and hide the query string. + logger.warning("The default web browser has been opened at %s. Please continue the login in the web browser. " + "If no web browser is available or if the web browser fails to open, use device code flow " + "with `az login --use-device-code`.", url.split('?')[0]) + # wait for callback from browser. while True: web_server.handle_request() @@ -1305,3 +1343,13 @@ if results.get('no_browser'): raise RuntimeError() return results + + +def _login_exception_handler(ex): + from requests.exceptions import InvalidURL + if isinstance(ex, InvalidURL): + import traceback + from azure.cli.core.azclierror import UnclassifiedUserFault + logger.debug('Invalid url when acquiring token\n%s', traceback.format_exc()) + raise UnclassifiedUserFault(error_msg='Invalid url when acquiring token', + recommendation='Please make sure the cloud is registered with valid url') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.14.2/azure/cli/core/adal_authentication.py new/azure-cli-core-2.15.0/azure/cli/core/adal_authentication.py --- old/azure-cli-core-2.14.2/azure/cli/core/adal_authentication.py 2020-11-09 06:56:54.000000000 +0100 +++ new/azure-cli-core-2.15.0/azure/cli/core/adal_authentication.py 2020-11-13 09:42:05.000000000 +0100 @@ -3,6 +3,7 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- +import datetime import time import requests import adal @@ -10,23 +11,35 @@ from msrest.authentication import Authentication from msrestazure.azure_active_directory import MSIAuthentication from azure.core.credentials import AccessToken -from azure.cli.core.util import in_cloud_console +from azure.cli.core.util import in_cloud_console, scopes_to_resource from knack.util import CLIError +from knack.log import get_logger + +logger = get_logger(__name__) class AdalAuthentication(Authentication): # pylint: disable=too-few-public-methods def __init__(self, token_retriever, external_tenant_token_retriever=None): + # DO NOT call _token_retriever from outside azure-cli-core. It is only available for user or + # Service Principal credential (AdalAuthentication), but not for Managed Identity credential + # (MSIAuthenticationWrapper). + # To retrieve a raw token, either call + # - Profile.get_raw_token, which is more direct + # - AdalAuthentication.get_token, which is designed for Track 2 SDKs self._token_retriever = token_retriever self._external_tenant_token_retriever = external_tenant_token_retriever - def _get_token(self): + def _get_token(self, sdk_resource=None): + """ + :param sdk_resource: `resource` converted from Track 2 SDK's `scopes` + """ external_tenant_tokens = None try: - scheme, token, full_token = self._token_retriever() + scheme, token, full_token = self._token_retriever(sdk_resource) if self._external_tenant_token_retriever: - external_tenant_tokens = self._external_tenant_token_retriever() + external_tenant_tokens = self._external_tenant_token_retriever(sdk_resource) except CLIError as err: if in_cloud_console(): AdalAuthentication._log_hostname() @@ -60,7 +73,16 @@ # This method is exposed for Azure Core. def get_token(self, *scopes, **kwargs): # pylint:disable=unused-argument - _, token, full_token, _ = self._get_token() + logger.debug("AdalAuthentication.get_token invoked by Track 2 SDK with scopes=%s", scopes) + + _, token, full_token, _ = self._get_token(_try_scopes_to_resource(scopes)) + + try: + expires_on = full_token['expiresOn'] + return AccessToken(token, int(datetime.datetime.strptime(expires_on, '%Y-%m-%d %H:%M:%S.%f').timestamp())) + except: # pylint: disable=bare-except + pass # To avoid crashes due to some unexpected token formats + try: return AccessToken(token, int(full_token['expiresIn'] + time.time())) except KeyError: # needed to deal with differing unserialized MSI token payload @@ -68,6 +90,7 @@ # This method is exposed for msrest. def signed_session(self, session=None): # pylint: disable=arguments-differ + logger.debug("AdalAuthentication.signed_session invoked by Track 1 SDK") session = session or super(AdalAuthentication, self).signed_session() scheme, token, _, external_tenant_tokens = self._get_token() @@ -82,8 +105,6 @@ @staticmethod def _log_hostname(): import socket - from knack.log import get_logger - logger = get_logger(__name__) logger.warning("A Cloud Shell credential problem occurred. When you report the issue with the error " "below, please mention the hostname '%s'", socket.gethostname()) @@ -91,13 +112,16 @@ class MSIAuthenticationWrapper(MSIAuthentication): # This method is exposed for Azure Core. Add *scopes, **kwargs to fit azure.core requirement def get_token(self, *scopes, **kwargs): # pylint:disable=unused-argument + logger.debug("MSIAuthenticationWrapper.get_token invoked by Track 2 SDK with scopes=%s", scopes) + resource = _try_scopes_to_resource(scopes) + if resource: + # If available, use resource provided by SDK + self.resource = resource self.set_token() return AccessToken(self.token['access_token'], int(self.token['expires_on'])) def set_token(self): import traceback - from knack.log import get_logger - logger = get_logger(__name__) from azure.cli.core.azclierror import AzureConnectionError, AzureResponseError try: super(MSIAuthenticationWrapper, self).set_token() @@ -109,11 +133,41 @@ except requests.exceptions.HTTPError as err: logger.debug('throw requests.exceptions.HTTPError when doing MSIAuthentication: \n%s', traceback.format_exc()) - raise AzureResponseError('Failed to connect to MSI. Please make sure MSI is configured correctly.\n' - 'Get Token request returned http error: {}, reason: {}' - .format(err.response.status, err.response.reason)) + try: + raise AzureResponseError('Failed to connect to MSI. Please make sure MSI is configured correctly.\n' + 'Get Token request returned http error: {}, reason: {}' + .format(err.response.status, err.response.reason)) + except AttributeError: + raise AzureResponseError('Failed to connect to MSI. Please make sure MSI is configured correctly.\n' + 'Get Token request returned: {}'.format(err.response)) except TimeoutError as err: logger.debug('throw TimeoutError when doing MSIAuthentication: \n%s', traceback.format_exc()) raise AzureConnectionError('MSI endpoint is not responding. Please make sure MSI is configured correctly.\n' 'Error detail: {}'.format(str(err))) + + def signed_session(self, session=None): + logger.debug("MSIAuthenticationWrapper.signed_session invoked by Track 1 SDK") + super().signed_session(session) + + +def _try_scopes_to_resource(scopes): + """Wrap scopes_to_resource to workaround some SDK issues.""" + + # Track 2 SDKs generated before https://github.com/Azure/autorest.python/pull/239 don't maintain + # credential_scopes and call `get_token` with empty scopes. + # As a workaround, return None so that the CLI-managed resource is used. + if not scopes: + logger.debug("No scope is provided by the SDK, use the CLI-managed resource.") + return None + + # Track 2 SDKs generated before https://github.com/Azure/autorest.python/pull/745 extend default + # credential_scopes with custom credential_scopes. Instead, credential_scopes should be replaced by + # custom credential_scopes. https://github.com/Azure/azure-sdk-for-python/issues/12947 + # As a workaround, remove the first one if there are multiple scopes provided. + if len(scopes) > 1: + logger.debug("Multiple scopes are provided by the SDK, discarding the first one: %s", scopes[0]) + return scopes_to_resource(scopes[1:]) + + # Exactly only one scope is provided + return scopes_to_resource(scopes) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.14.2/azure/cli/core/azclierror.py new/azure-cli-core-2.15.0/azure/cli/core/azclierror.py --- old/azure-cli-core-2.14.2/azure/cli/core/azclierror.py 2020-11-09 06:56:54.000000000 +0100 +++ new/azure-cli-core-2.15.0/azure/cli/core/azclierror.py 2020-11-13 09:42:05.000000000 +0100 @@ -15,15 +15,15 @@ # 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. +# For example, CloudError, CLIError and ValidationError 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): - """ Base class for all the AzureCLI defined error classes. """ + """ Base class for all the AzureCLI defined error classes. + DO NOT raise this error class in your codes. """ def __init__(self, error_msg, recommendation=None): # error message @@ -32,17 +32,17 @@ # 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 + self.set_recommendation(recommendation) # exception trace for the error self.exception_trace = None super().__init__(error_msg) def set_recommendation(self, recommendation): - self.recommendations.append(recommendation) + if isinstance(recommendation, str): + self.recommendations.append(recommendation) + elif isinstance(recommendation, list): + self.recommendations.extend(recommendation) def set_exception_trace(self, exception_trace): self.exception_trace = exception_trace @@ -68,35 +68,44 @@ # 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. """ + """ Users should be responsible for the errors. + DO NOT raise this error class in your codes. """ 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. """ + """ Azure Services should be responsible for the errors. + DO NOT raise this error class in your codes. """ def send_telemetry(self): super().send_telemetry() telemetry.set_failure(self.error_msg) class ClientError(AzCLIError): - """ AzureCLI should be responsible for the errors. """ + """ AzureCLI should be responsible for the errors. + DO NOT raise this error class in your codes. """ def send_telemetry(self): super().send_telemetry() telemetry.set_failure(self.error_msg) if self.exception_trace: telemetry.set_exception(self.exception_trace, '') + + +class UnknownError(AzCLIError): + """ Unclear errors, could not know who should be responsible for the errors. + DO NOT raise this error class in your codes. """ + def send_telemetry(self): + super().send_telemetry() + telemetry.set_failure(self.error_msg) # 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 +# Specific categories of the AzureCLI error types +# 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. """ @@ -115,7 +124,7 @@ class MutuallyExclusiveArgumentError(UserFault): - """ Arguments can not be specfied together. """ + """ Arguments can not be specified together. """ pass @@ -124,10 +133,10 @@ pass -class ArgumentParseError(UserFault): - """ Fallback of the argument parsing related errors. +class ArgumentUsageError(UserFault): + """ Fallback of the argument usage related errors. Avoid using this class unless the error can not be classified - into the above Argument related error types. """ + into the Argument related specific error types. """ pass @@ -139,10 +148,12 @@ class UnauthorizedError(UserFault): """ Unauthorized request: 401 error """ + pass class ForbiddenError(UserFault): """ Service refuse to response: 403 error """ + pass class ResourceNotFoundError(UserFault): @@ -158,7 +169,8 @@ 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. """ + into the Response related specific error types. """ + pass # Request related error types @@ -171,20 +183,13 @@ """ 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. """ + into the Request related specific errors types. """ pass -# CLI internal error type -class CLIInternalError(ClientError): - """ AzureCLI internal error """ +# File operation related error types +class FileOperationError(UserFault): + """ For file or directory operation related errors. """ pass @@ -194,11 +199,30 @@ 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. """ +# ARM template related error types +class InvalidTemplateError(UserFault): + """ ARM template validation fails. It could be caused by incorrect template files or parameters """ + pass + + +class DeploymentError(UserFault): + """ ARM template deployment fails. Template file is valid, and error occurs in deployment. """ + pass + + +# 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 specific error types. """ + pass + + +class UnclassifiedUserFault(UserFault): + """ Fallback of the UserFault related error types. + Avoid using this class unless the error can not be classified into + the UserFault related specific error types. + """ def print_error(self): from azure.cli.core.azlogging import CommandLoggerContext with CommandLoggerContext(logger): @@ -209,4 +233,10 @@ for recommendation in self.recommendations: print(recommendation, file=sys.stderr) + +# CLI internal error type +class CLIInternalError(ClientError): + """ AzureCLI internal error """ + pass + # endregion diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.14.2/azure/cli/core/cloud.py new/azure-cli-core-2.15.0/azure/cli/core/cloud.py --- old/azure-cli-core-2.14.2/azure/cli/core/cloud.py 2020-11-09 06:56:54.000000000 +0100 +++ new/azure-cli-core-2.15.0/azure/cli/core/cloud.py 2020-11-13 09:42:05.000000000 +0100 @@ -346,7 +346,7 @@ 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.azure.cn', portal='https://portal.azure.cn'), suffixes=CloudSuffixes( storage_endpoint='core.chinacloudapi.cn', @@ -377,6 +377,7 @@ 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', + synapse_analytics_resource_id='https://dev.azuresynapse.usgovcloudapi.net', portal='https://portal.azure.us'), suffixes=CloudSuffixes( storage_endpoint='core.usgovcloudapi.net', @@ -387,7 +388,8 @@ mysql_server_endpoint='.mysql.database.usgovcloudapi.net', postgresql_server_endpoint='.postgres.database.usgovcloudapi.net', mariadb_server_endpoint='.mariadb.database.usgovcloudapi.net', - acr_login_server_endpoint='.azurecr.us')) + acr_login_server_endpoint='.azurecr.us', + synapse_analytics_endpoint='.dev.azuresynapse.usgovcloudapi.net')) AZURE_GERMAN_CLOUD = Cloud( 'AzureGermanCloud', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.14.2/azure/cli/core/commands/__init__.py new/azure-cli-core-2.15.0/azure/cli/core/commands/__init__.py --- old/azure-cli-core-2.14.2/azure/cli/core/commands/__init__.py 2020-11-09 06:56:54.000000000 +0100 +++ new/azure-cli-core-2.15.0/azure/cli/core/commands/__init__.py 2020-11-13 09:42:05.000000000 +0100 @@ -706,8 +706,7 @@ return event_data['result'] except Exception as ex: # pylint: disable=broad-except if cmd_copy.exception_handler: - cmd_copy.exception_handler(ex) - return CommandResultItem(None, exit_code=1, error=ex) + return cmd_copy.exception_handler(ex) six.reraise(*sys.exc_info()) def _run_jobs_serially(self, jobs, ids): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.14.2/azure/cli/core/commands/client_factory.py new/azure-cli-core-2.15.0/azure/cli/core/commands/client_factory.py --- old/azure-cli-core-2.14.2/azure/cli/core/commands/client_factory.py 2020-11-09 06:56:54.000000000 +0100 +++ new/azure-cli-core-2.15.0/azure/cli/core/commands/client_factory.py 2020-11-13 09:42:05.000000000 +0100 @@ -110,12 +110,21 @@ client.config.generate_client_request_id = 'x-ms-client-request-id' not in cli_ctx.data['headers'] -def configure_common_settings_track2(cli_ctx): +def _prepare_client_kwargs_track2(cli_ctx): + """Prepare kwargs for Track 2 SDK client.""" client_kwargs = {} + # Prepare connection_verify to change SSL verification behavior, used by ConnectionConfiguration client_kwargs.update(_debug.change_ssl_cert_verification_track2()) + # Enable NetworkTraceLoggingPolicy which logs all headers (except Authorization) without being redacted client_kwargs['logging_enable'] = True + + # Disable ARMHttpLoggingPolicy which logs only allowed headers + from azure.core.pipeline.policies import SansIOHTTPPolicy + client_kwargs['http_logging_policy'] = SansIOHTTPPolicy() + + # Prepare User-Agent header, used by UserAgentPolicy client_kwargs['user_agent'] = get_az_user_agent() try: @@ -125,13 +134,20 @@ except KeyError: pass + # Prepare custom headers, used by HeadersPolicy headers = dict(cli_ctx.data['headers']) + + # - Prepare CommandName header command_name_suffix = ';completer-request' if cli_ctx.data['completer_active'] else '' headers['CommandName'] = "{}{}".format(cli_ctx.data['command'], command_name_suffix) + + # - Prepare ParameterSetName header if cli_ctx.data.get('safe_params'): headers['ParameterSetName'] = ' '.join(cli_ctx.data['safe_params']) + client_kwargs['headers'] = headers + # Prepare x-ms-client-request-id header, used by RequestIdPolicy if 'x-ms-client-request-id' in cli_ctx.data['headers']: client_kwargs['request_id'] = cli_ctx.data['headers']['x-ms-client-request-id'] @@ -150,6 +166,7 @@ aux_tenants=None, **kwargs): from azure.cli.core._profile import Profile + from azure.cli.core.util import resource_to_scopes logger.debug('Getting management service client client_type=%s', client_type.__name__) resource = resource or cli_ctx.cloud.endpoints.active_directory_resource_id profile = Profile(cli_ctx=cli_ctx) @@ -168,7 +185,8 @@ client_kwargs.update(kwargs) if is_track2(client_type): - client_kwargs.update(configure_common_settings_track2(cli_ctx)) + client_kwargs.update(_prepare_client_kwargs_track2(cli_ctx)) + client_kwargs['credential_scopes'] = resource_to_scopes(resource) if subscription_bound: client = client_type(cred, subscription_id, **client_kwargs) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.14.2/azure/cli/core/parser.py new/azure-cli-core-2.15.0/azure/cli/core/parser.py --- old/azure-cli-core-2.14.2/azure/cli/core/parser.py 2020-11-09 06:56:54.000000000 +0100 +++ new/azure-cli-core-2.15.0/azure/cli/core/parser.py 2020-11-13 09:42:05.000000000 +0100 @@ -5,7 +5,6 @@ from __future__ import print_function -import sys import difflib import argparse @@ -21,7 +20,7 @@ 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 ArgumentUsageError from azure.cli.core.azclierror import CommandNotFoundError from azure.cli.core.azclierror import ValidationError @@ -69,12 +68,6 @@ class AzCliCommandParser(CLICommandParser): """ArgumentParser implementation specialized for the Azure CLI utility.""" - @staticmethod - def recommendation_provider(version, command, parameters, extension): # pylint: disable=unused-argument - logger.debug("recommendation_provider: version: %s, command: %s, parameters: %s, extension: %s", - version, command, parameters, extension) - return [] - def __init__(self, cli_ctx=None, cli_help=None, **kwargs): self.command_source = kwargs.pop('_command_source', None) self._raw_arguments = None @@ -172,7 +165,7 @@ recommender.set_help_examples(self.get_examples(self.prog)) recommendation = recommender.recommend_a_command() - az_error = ArgumentParseError(message) + az_error = ArgumentUsageError(message) if 'unrecognized arguments' in message: az_error = UnrecognizedArgumentError(message) elif 'arguments are required' in message: @@ -188,11 +181,6 @@ az_error.set_recommendation(OVERVIEW_REFERENCE.format(command=self.prog)) az_error.print_error() az_error.send_telemetry() - - # For ai-did-you-mean-this - failure_recovery_recommendations = self._get_failure_recovery_recommendations() - self._suggestion_msg.extend(failure_recovery_recommendations) - self._print_suggestion_msg(sys.stderr) self.exit(2) def format_help(self): @@ -289,25 +277,12 @@ return command, parameters, extension - def _get_failure_recovery_recommendations(self, action=None, **kwargs): - # Gets failure recovery recommendations - from azure.cli.core import __version__ as core_version - failure_recovery_arguments = self._get_failure_recovery_arguments(action) - recommendations = AzCliCommandParser.recommendation_provider(core_version, - *failure_recovery_arguments, - **kwargs) - return recommendations - def _get_values(self, action, arg_strings): value = super(AzCliCommandParser, self)._get_values(action, arg_strings) if action.dest and isinstance(action.dest, str) and not action.dest.startswith('_'): self.specified_arguments.append(action.dest) return value - def _print_suggestion_msg(self, file=None): - if self._suggestion_msg: - print('\n'.join(self._suggestion_msg), file=file) - def parse_known_args(self, args=None, namespace=None): # retrieve the raw argument list in case parsing known arguments fails. self._raw_arguments = args @@ -482,7 +457,7 @@ if candidates: az_error.set_recommendation("Did you mean '{}' ?".format(candidates[0])) - # recommand a command for user + # recommend a command for user recommender = CommandRecommender(*command_arguments, error_msg, cli_ctx) recommender.set_help_examples(self.get_examples(command_name_inferred)) recommended_command = recommender.recommend_a_command() @@ -497,11 +472,8 @@ az_error.set_recommendation(OVERVIEW_REFERENCE.format(command=self.prog)) - az_error.print_error() - az_error.send_telemetry() - if not caused_by_extension_not_installed: - failure_recovery_recommendations = self._get_failure_recovery_recommendations(action) - self._suggestion_msg.extend(failure_recovery_recommendations) - self._print_suggestion_msg(sys.stderr) + az_error.print_error() + az_error.send_telemetry() + self.exit(2) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.14.2/azure/cli/core/util.py new/azure-cli-core-2.15.0/azure/cli/core/util.py --- old/azure-cli-core-2.14.2/azure/cli/core/util.py 2020-11-09 06:56:54.000000000 +0100 +++ new/azure-cli-core-2.15.0/azure/cli/core/util.py 2020-11-13 09:42:05.000000000 +0100 @@ -55,7 +55,7 @@ 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 jmespath.exceptions import JMESPathError from msrestazure.azure_exceptions import CloudError from msrest.exceptions import HttpOperationError, ValidationError, ClientRequestError from azure.cli.core.azlogging import CommandLoggerContext @@ -76,7 +76,7 @@ if isinstance(ex, azclierror.AzCLIError): az_error = ex - elif isinstance(ex, JMESPathTypeError): + elif isinstance(ex, JMESPathError): error_msg = "Invalid jmespath query supplied for `--query`: {}".format(error_msg) az_error = azclierror.InvalidArgumentValueError(error_msg) az_error.set_recommendation(QUERY_REFERENCE) @@ -96,8 +96,8 @@ az_error = azclierror.ValidationError(error_msg) elif isinstance(ex, CLIError): - # TODO: Fine-grained analysis here for Unknown error - az_error = azclierror.UnknownError(error_msg) + # TODO: Fine-grained analysis here + az_error = azclierror.UnclassifiedUserFault(error_msg) elif isinstance(ex, AzureError): if extract_common_error_message(ex): @@ -1165,3 +1165,36 @@ refresh_known_clouds() except Exception as ex: # pylint: disable=broad-except logger.warning(ex) + + +def resource_to_scopes(resource): + """Convert the ADAL resource ID to MSAL scopes by appending the /.default suffix and return a list. + For example: + 'https://management.core.windows.net/' -> ['https://management.core.windows.net//.default'] + 'https://managedhsm.azure.com' -> ['https://managedhsm.azure.com/.default'] + + :param resource: The ADAL resource ID + :return: A list of scopes + """ + # https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#trailing-slash-and-default + # We should not trim the trailing slash, like in https://management.azure.com/ + # In other word, the trailing slash should be preserved and scope should be https://management.azure.com//.default + scope = resource + '/.default' + return [scope] + + +def scopes_to_resource(scopes): + """Convert MSAL scopes to ADAL resource by stripping the /.default suffix and return a str. + For example: + ['https://management.core.windows.net//.default'] -> 'https://management.core.windows.net/' + ['https://managedhsm.azure.com/.default'] -> 'https://managedhsm.azure.com' + + :param scopes: The MSAL scopes. It can be a list or tuple of string + :return: The ADAL resource + :rtype: str + """ + scope = scopes[0] + if scope.endswith("/.default"): + scope = scope[:-len("/.default")] + + return scope diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.14.2/azure_cli_core.egg-info/PKG-INFO new/azure-cli-core-2.15.0/azure_cli_core.egg-info/PKG-INFO --- old/azure-cli-core-2.14.2/azure_cli_core.egg-info/PKG-INFO 2020-11-09 06:57:09.000000000 +0100 +++ new/azure-cli-core-2.15.0/azure_cli_core.egg-info/PKG-INFO 2020-11-13 09:42:18.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: azure-cli-core -Version: 2.14.2 +Version: 2.15.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.15.0 + ++++++ + * Upgrade azure-mgmt-core to 1.2.1 (#15780) + 2.14.2 ++++++ * No changes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.14.2/azure_cli_core.egg-info/requires.txt new/azure-cli-core-2.15.0/azure_cli_core.egg-info/requires.txt --- old/azure-cli-core-2.14.2/azure_cli_core.egg-info/requires.txt 2020-11-09 06:57:09.000000000 +0100 +++ new/azure-cli-core-2.15.0/azure_cli_core.egg-info/requires.txt 2020-11-13 09:42:18.000000000 +0100 @@ -16,7 +16,7 @@ six~=1.12 pkginfo>=1.5.0.1 azure-mgmt-resource==10.2.0 -azure-mgmt-core==1.2.0 +azure-mgmt-core==1.2.1 [:python_version<"3.0"] futures diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-core-2.14.2/setup.py new/azure-cli-core-2.15.0/setup.py --- old/azure-cli-core-2.14.2/setup.py 2020-11-09 06:56:54.000000000 +0100 +++ new/azure-cli-core-2.15.0/setup.py 2020-11-13 09:42:05.000000000 +0100 @@ -9,7 +9,7 @@ from codecs import open from setuptools import setup -VERSION = "2.14.2" +VERSION = "2.15.0" # If we have source, validate that our version numbers match # This should prevent uploading releases with mismatched versions. @@ -61,7 +61,7 @@ 'six~=1.12', 'pkginfo>=1.5.0.1', 'azure-mgmt-resource==10.2.0', - 'azure-mgmt-core==1.2.0' + 'azure-mgmt-core==1.2.1' ] TESTS_REQUIRE = [ _______________________________________________ openSUSE Commits mailing list -- commit@lists.opensuse.org To unsubscribe, email commit-le...@lists.opensuse.org List Netiquette: https://en.opensuse.org/openSUSE:Mailing_list_netiquette List Archives: https://lists.opensuse.org/archives/list/commit@lists.opensuse.org