Hello community,

here is the log from the commit of package azure-cli-core for openSUSE:Factory 
checked in at 2020-08-19 18:52:52
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/azure-cli-core (Old)
 and      /work/SRC/openSUSE:Factory/.azure-cli-core.new.3399 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "azure-cli-core"

Wed Aug 19 18:52:52 2020 rev:17 rq:827685 version:2.10.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/azure-cli-core/azure-cli-core.changes    
2020-07-26 16:19:02.192791035 +0200
+++ /work/SRC/openSUSE:Factory/.azure-cli-core.new.3399/azure-cli-core.changes  
2020-08-19 18:54:44.499780790 +0200
@@ -1,0 +2,9 @@
+Tue Aug 18 21:25:40 UTC 2020 - John Paul Adrian Glaubitz 
<adrian.glaub...@suse.com>
+
+- New upstream release (boo#1175289)
+  + Version 2.10.1
+  + For detailed information about changes see the
+    HISTORY.txt file provided with this package
+- Update Requires from setup.py
+
+-------------------------------------------------------------------

Old:
----
  azure-cli-core-2.9.1.tar.gz

New:
----
  azure-cli-core-2.10.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ azure-cli-core.spec ++++++
--- /var/tmp/diff_new_pack.yuF43K/_old  2020-08-19 18:54:47.419782342 +0200
+++ /var/tmp/diff_new_pack.yuF43K/_new  2020-08-19 18:54:47.423782344 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           azure-cli-core
-Version:        2.9.1
+Version:        2.10.1
 Release:        0
 Summary:        Microsoft Azure CLI Core Module
 License:        MIT
@@ -43,14 +43,14 @@
 Requires:       python3-azure-mgmt-core < 2.0.0
 Requires:       python3-azure-mgmt-core >= 1.0.0
 Requires:       python3-azure-mgmt-resource < 11.0.0
-Requires:       python3-azure-mgmt-resource >= 10.0.0
+Requires:       python3-azure-mgmt-resource >= 10.1.0
 Requires:       python3-azure-nspkg >= 3.0.0
 Requires:       python3-colorama >= 0.4.1
 Requires:       python3-humanfriendly < 9.0
 Requires:       python3-humanfriendly >= 4.7
 Requires:       python3-jmespath
 Requires:       python3-knack < 1.0.0
-Requires:       python3-knack >= 0.7.1
+Requires:       python3-knack >= 0.7.2
 Requires:       python3-msal < 2.0.0
 Requires:       python3-msal >= 1.0.0
 Requires:       python3-msal-extensions < 1.0.0

++++++ azure-cli-core-2.9.1.tar.gz -> azure-cli-core-2.10.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.9.1/HISTORY.rst 
new/azure-cli-core-2.10.1/HISTORY.rst
--- old/azure-cli-core-2.9.1/HISTORY.rst        2020-07-16 10:09:55.000000000 
+0200
+++ new/azure-cli-core-2.10.1/HISTORY.rst       2020-08-06 10:46:59.000000000 
+0200
@@ -3,6 +3,14 @@
 Release History
 ===============
 
+2.10.1
+++++++
+* Minor fixes
+
+2.10.0
+++++++
+* Minor fixes
+
 2.9.1
 ++++++
 * Minor fixes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.9.1/PKG-INFO 
new/azure-cli-core-2.10.1/PKG-INFO
--- old/azure-cli-core-2.9.1/PKG-INFO   2020-07-16 10:10:08.000000000 +0200
+++ new/azure-cli-core-2.10.1/PKG-INFO  2020-08-06 10:47:07.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: azure-cli-core
-Version: 2.9.1
+Version: 2.10.1
 Summary: Microsoft Azure Command-Line Tools Core Module
 Home-page: https://github.com/Azure/azure-cli
 Author: Microsoft Corporation
@@ -15,6 +15,14 @@
         Release History
         ===============
         
+        2.10.1
+        ++++++
+        * Minor fixes
+        
+        2.10.0
+        ++++++
+        * Minor fixes
+        
         2.9.1
         ++++++
         * Minor fixes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.9.1/azure/cli/core/__init__.py 
new/azure-cli-core-2.10.1/azure/cli/core/__init__.py
--- old/azure-cli-core-2.9.1/azure/cli/core/__init__.py 2020-07-16 
10:09:55.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure/cli/core/__init__.py        2020-08-06 
10:46:59.000000000 +0200
@@ -6,7 +6,7 @@
 
 from __future__ import print_function
 
-__version__ = "2.9.1"
+__version__ = "2.10.1"
 
 import os
 import sys
@@ -373,18 +373,6 @@
                             res.append(sup)
             return res
 
-        def _roughly_parse_command(args):
-            # Roughly parse the command part: <az vm create> --name vm1
-            # Similar to 
knack.invocation.CommandInvoker._rudimentary_get_command, but we don't need to 
bother with
-            # positional args
-            nouns = []
-            for arg in args:
-                if arg and arg[0] != '-':
-                    nouns.append(arg)
-                else:
-                    break
-            return ' '.join(nouns).lower()
-
         # Clear the tables to make this method idempotent
         self.command_group_table.clear()
         self.command_table.clear()
@@ -404,17 +392,32 @@
                 _update_command_table_from_extensions([], index_extensions)
 
                 logger.debug("Loaded %d groups, %d commands.", 
len(self.command_group_table), len(self.command_table))
+                from azure.cli.core.util import roughly_parse_command
                 # The index may be outdated. Make sure the command appears in 
the loaded command table
-                command_str = _roughly_parse_command(args)
-                if command_str in self.command_table:
-                    logger.debug("Found a match in the command table for 
'%s'", command_str)
-                    return self.command_table
-                if command_str in self.command_group_table:
-                    logger.debug("Found a match in the command group table for 
'%s'", command_str)
+                raw_cmd = roughly_parse_command(args)
+                for cmd in self.command_table:
+                    if raw_cmd.startswith(cmd):
+                        # For commands with positional arguments, the raw 
command won't match the one in the
+                        # command table. For example, `az find vm create` 
won't exist in the command table, but the
+                        # corresponding command should be `az find`.
+                        # raw command  : az find vm create
+                        # command table: az find
+                        # remaining    :         vm create
+                        logger.debug("Found a match in the command table.")
+                        logger.debug("Raw command  : %s", raw_cmd)
+                        logger.debug("Command table: %s", cmd)
+                        remaining = raw_cmd[len(cmd) + 1:]
+                        if remaining:
+                            logger.debug("remaining    : %s %s", ' ' * 
len(cmd), remaining)
+                        return self.command_table
+                # For command group, it must be an exact match, as no 
positional argument is supported by
+                # command group operations.
+                if raw_cmd in self.command_group_table:
+                    logger.debug("Found a match in the command group table for 
'%s'.", raw_cmd)
                     return self.command_table
 
-                logger.debug("Could not find a match in the command table for 
'%s'. The index may be outdated",
-                             command_str)
+                logger.debug("Could not find a match in the command or command 
group table for '%s'. "
+                             "The index may be outdated.", raw_cmd)
             else:
                 logger.debug("No module found from index for '%s'", args)
 
@@ -579,7 +582,7 @@
         logger.debug("Command index has been invalidated.")
 
 
-class ModExtensionSuppress(object):  # pylint: disable=too-few-public-methods
+class ModExtensionSuppress:  # pylint: disable=too-few-public-methods
 
     def __init__(self, mod_name, suppress_extension_name, 
suppress_up_to_version, reason=None, recommend_remove=False,
                  recommend_update=False):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.9.1/azure/cli/core/_help_loaders.py 
new/azure-cli-core-2.10.1/azure/cli/core/_help_loaders.py
--- old/azure-cli-core-2.9.1/azure/cli/core/_help_loaders.py    2020-07-16 
10:09:55.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure/cli/core/_help_loaders.py   2020-08-06 
10:46:59.000000000 +0200
@@ -5,13 +5,14 @@
 
 import abc
 import os
-import yaml
 
 from azure.cli.core._help import (HelpExample, CliHelpFile)
 
 from knack.util import CLIError
 from knack.log import get_logger
 
+import yaml
+
 logger = get_logger(__name__)
 
 try:
@@ -93,7 +94,7 @@
         help_obj.parameters = loaded_params
 
 
-class YamlLoaderMixin(object):  # pylint:disable=too-few-public-methods
+class YamlLoaderMixin:  # pylint:disable=too-few-public-methods
     """A class containing helper methods for Yaml Loaders."""
 
     # get the list of yaml help file names for the command or group
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.9.1/azure/cli/core/_profile.py 
new/azure-cli-core-2.10.1/azure/cli/core/_profile.py
--- old/azure-cli-core-2.9.1/azure/cli/core/_profile.py 2020-07-16 
10:09:55.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure/cli/core/_profile.py        2020-08-06 
10:46:59.000000000 +0200
@@ -15,14 +15,15 @@
 from copy import deepcopy
 from enum import Enum
 
+from knack.log import get_logger
+from knack.util import CLIError
+
 from azure.cli.core._environment import get_config_dir
 from azure.cli.core._session import ACCOUNT
 from azure.cli.core.util import get_file_json, in_cloud_console, 
open_page_in_browser, can_launch_browser,\
     is_windows, is_wsl
 from azure.cli.core.cloud import get_active_cloud, set_cloud_subscription
 
-from knack.log import get_logger
-from knack.util import CLIError
 
 logger = get_logger(__name__)
 
@@ -139,7 +140,7 @@
 
 
 # pylint: disable=too-many-lines,too-many-instance-attributes
-class Profile(object):
+class Profile:
 
     _global_creds_cache = None
 
@@ -745,9 +746,12 @@
         endpoint_mappings['sql_management'] = 'sqlManagementEndpointUrl'
         endpoint_mappings['gallery'] = 'galleryEndpointUrl'
         endpoint_mappings['management'] = 'managementEndpointUrl'
-
+        from azure.cli.core.cloud import CloudEndpointNotSetException
         for e in endpoint_mappings:
-            result[endpoint_mappings[e]] = 
getattr(get_active_cloud(self.cli_ctx).endpoints, e)
+            try:
+                result[endpoint_mappings[e]] = 
getattr(get_active_cloud(self.cli_ctx).endpoints, e)
+            except CloudEndpointNotSetException:
+                result[endpoint_mappings[e]] = None
         return result
 
     def get_installation_id(self):
@@ -759,7 +763,7 @@
         return installation_id
 
 
-class MsiAccountTypes(object):
+class MsiAccountTypes:
     # pylint: disable=no-method-argument,no-self-argument
     system_assigned = 'MSI'
     user_assigned_client_id = 'MSIClient'
@@ -785,7 +789,7 @@
         raise ValueError("unrecognized msi account name 
'{}'".format(cli_account_name))
 
 
-class SubscriptionFinder(object):
+class SubscriptionFinder:
     '''finds all subscriptions for a user or service principal'''
 
     def __init__(self, cli_ctx, auth_context_factory, adal_token_cache, 
arm_client_factory=None):
@@ -970,7 +974,7 @@
         return all_subscriptions
 
 
-class CredsCache(object):
+class CredsCache:
     '''Caches AAD tokena and service principal secrets, and persistence will
     also be handled
     '''
@@ -1128,7 +1132,7 @@
         _delete_file(self._token_file)
 
 
-class ServicePrincipalAuth(object):
+class ServicePrincipalAuth:
 
     def __init__(self, password_arg_value, use_cert_sn_issuer=None):
         if not password_arg_value:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.9.1/azure/cli/core/_session.py 
new/azure-cli-core-2.10.1/azure/cli/core/_session.py
--- old/azure-cli-core-2.9.1/azure/cli/core/_session.py 2020-07-16 
10:09:55.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure/cli/core/_session.py        2020-08-06 
10:46:59.000000000 +0200
@@ -113,3 +113,6 @@
 # it could be lagged behind and can be used to check whether
 # an upgrade of azure-cli happens
 VERSIONS = Session()
+
+# EXT_CMD_TREE provides command to extension name mapping
+EXT_CMD_TREE = Session()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.9.1/azure/cli/core/azlogging.py 
new/azure-cli-core-2.10.1/azure/cli/core/azlogging.py
--- old/azure-cli-core-2.9.1/azure/cli/core/azlogging.py        2020-07-16 
10:09:55.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure/cli/core/azlogging.py       2020-08-06 
10:46:59.000000000 +0200
@@ -191,7 +191,7 @@
             self.command_metadata_logger = None
 
 
-class CommandLoggerContext(object):
+class CommandLoggerContext:
     def __init__(self, module_logger):
         self.logger = module_logger
         self.hdlr = logging.getLogger(AzCliLogging._COMMAND_METADATA_LOGGER)  
# pylint: disable=protected-access
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.9.1/azure/cli/core/cloud.py 
new/azure-cli-core-2.10.1/azure/cli/core/cloud.py
--- old/azure-cli-core-2.9.1/azure/cli/core/cloud.py    2020-07-16 
10:09:55.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure/cli/core/cloud.py   2020-08-06 
10:46:59.000000000 +0200
@@ -2,6 +2,7 @@
 # Copyright (c) Microsoft Corporation. All rights reserved.
 # Licensed under the MIT License. See License.txt in the project root for 
license information.
 # 
--------------------------------------------------------------------------------------------
+# pylint: disable=line-too-long
 
 import os
 import json
@@ -53,7 +54,7 @@
     pass
 
 
-class CloudEndpoints(object):  # pylint: 
disable=too-few-public-methods,too-many-instance-attributes
+class CloudEndpoints:  # pylint: 
disable=too-few-public-methods,too-many-instance-attributes
 
     def __init__(self,
                  management=None,
@@ -71,7 +72,8 @@
                  ossrdbms_resource_id=None,
                  log_analytics_resource_id=None,
                  app_insights_resource_id=None,
-                 app_insights_telemetry_channel_resource_id=None):
+                 app_insights_telemetry_channel_resource_id=None,
+                 synapse_analytics_resource_id=None):
         # Attribute names are significant. They are used when 
storing/retrieving clouds from config
         self.management = management
         self.resource_manager = resource_manager
@@ -89,6 +91,7 @@
         self.log_analytics_resource_id = log_analytics_resource_id
         self.app_insights_resource_id = app_insights_resource_id
         self.app_insights_telemetry_channel_resource_id = 
app_insights_telemetry_channel_resource_id
+        self.synapse_analytics_resource_id = synapse_analytics_resource_id
 
     def has_endpoint_set(self, endpoint_name):
         try:
@@ -110,7 +113,7 @@
         return val
 
 
-class CloudSuffixes(object):  # pylint: 
disable=too-few-public-methods,too-many-instance-attributes
+class CloudSuffixes:  # pylint: 
disable=too-few-public-methods,too-many-instance-attributes
 
     def __init__(self,
                  storage_endpoint=None,
@@ -122,7 +125,8 @@
                  acr_login_server_endpoint=None,
                  mysql_server_endpoint=None,
                  postgresql_server_endpoint=None,
-                 mariadb_server_endpoint=None):
+                 mariadb_server_endpoint=None,
+                 synapse_analytics_endpoint=None):
         # Attribute names are significant. They are used when 
storing/retrieving clouds from config
         self.storage_endpoint = storage_endpoint
         self.storage_sync_endpoint = storage_sync_endpoint
@@ -134,6 +138,7 @@
         self.azure_datalake_store_file_system_endpoint = 
azure_datalake_store_file_system_endpoint
         self.azure_datalake_analytics_catalog_and_job_endpoint = 
azure_datalake_analytics_catalog_and_job_endpoint
         self.acr_login_server_endpoint = acr_login_server_endpoint
+        self.synapse_analytics_endpoint = synapse_analytics_endpoint
 
     def __getattribute__(self, name):
         val = object.__getattribute__(self, name)
@@ -170,17 +175,90 @@
         'AzureCloud': 'afs.azure.net',
         'AzureUSGovernment': 'afs.azure.us',
     }
-    return storage_sync_endpoint_mapper.get(cloud_name, 'afs.azure.net')
+    return storage_sync_endpoint_mapper.get(cloud_name, None)
+
+
+def _get_synapse_analytics_endpoint(cloud_name):
+    synapse_analytics_endpoint_mapper = {
+        'AzureCloud': 'dev.azuresynapse.net',
+        'AzureChinaCloud': 'dev.azuresynapse.azure.cn'
+    }
+    return synapse_analytics_endpoint_mapper.get(cloud_name, None)
+
+
+def _get_database_server_endpoint(sql_server_hostname, cloud_name):
+    def _concat_db_server_endpoint(db_prefix):
+        if cloud_name == 'AzureCloud':
+            return db_prefix + '.database.azure.com'
+        if not sql_server_hostname:
+            return None
+        return db_prefix + sql_server_hostname
+    return _concat_db_server_endpoint
+
+
+def _get_app_insights_telemetry_channel_resource_id(cloud_name):
+    app_insights_telemetry_channel_resource_id_mapper = {
+        'AzureCloud': 'https://dc.applicationinsights.azure.com/v2/track',
+        'AzureChinaCloud': 'https://dc.applicationinsights.azure.cn/v2/track',
+        'AzureUSGovernment': 'https://dc.applicationinsights.us/v2/track'
+    }
+    return app_insights_telemetry_channel_resource_id_mapper.get(cloud_name, 
None)
+
+
+def _get_log_analytics_resource_id(cloud_name):
+    log_analytics_resource_id_mapper = {
+        'AzureCloud': 'https://api.loganalytics.io',
+        'AzureChinaCloud': 'https://api.loganalytics.azure.cn',
+        'AzureUSGovernment': 'https://api.loganalytics.us'
+    }
+    return log_analytics_resource_id_mapper.get(cloud_name, None)
+
+
+def _get_app_insights_resource_id(cloud_name):
+    app_insights_resource_id_mapper = {
+        'AzureCloud': 'https://api.applicationinsights.io',
+        'AzureChinaCloud': 'https://api.applicationinsights.azure.cn',
+        'AzureUSGovernment': 'https://api.applicationinsights.us'
+    }
+    return app_insights_resource_id_mapper.get(cloud_name, None)
+
+
+def _get_synapse_analytics_resource_id(cloud_name):
+    synapse_analytics_resource_id_mapper = {
+        'AzureCloud': 'https://dev.azuresynapse.net',
+        'AzureChinaCloud': 'https://dev.azuresynapse.net'
+    }
+    return synapse_analytics_resource_id_mapper.get(cloud_name, None)
 
 
 def _convert_arm_to_cli(arm_cloud_metadata_dict):
     cli_cloud_metadata_dict = {}
     for cloud in arm_cloud_metadata_dict:
         cli_cloud_metadata_dict[cloud['name']] = _arm_to_cli_mapper(cloud)
+    if 'AzureCloud' in cli_cloud_metadata_dict:
+        cli_cloud_metadata_dict['AzureCloud'].endpoints.active_directory = 
'https://login.microsoftonline.com'  # change once active_directory is fixed in 
ARM for the public cloud
     return cli_cloud_metadata_dict
 
 
+def _add_starting_dot(suffix):
+    return suffix if not suffix or suffix.startswith('.') else '.' + suffix
+
+
+def _get_arm_endpoint(arm_dict, is_suffix=False):
+    def _get_processed_arm_endpoint(name, add_dot=False, fallback_value=None):
+        if is_suffix:
+            return (_add_starting_dot(arm_dict['suffixes'][name]) if add_dot 
else arm_dict['suffixes'][name]) if name in arm_dict['suffixes'] else 
fallback_value
+        return arm_dict[name] if name in arm_dict else fallback_value
+    return _get_processed_arm_endpoint
+
+
 def _arm_to_cli_mapper(arm_dict):
+    get_endpoint = _get_arm_endpoint(arm_dict)
+    get_suffix = _get_arm_endpoint(arm_dict, is_suffix=True)
+
+    sql_server_hostname = get_suffix('sqlServerHostname', add_dot=True)
+    get_db_server_endpoint = 
_get_database_server_endpoint(sql_server_hostname, arm_dict['name'])
+
     return Cloud(
         arm_dict['name'],
         endpoints=CloudEndpoints(
@@ -192,27 +270,30 @@
             active_directory=arm_dict['authentication']['loginEndpoint'],
             
active_directory_resource_id=arm_dict['authentication']['audiences'][0],
             active_directory_graph_resource_id=arm_dict['graphAudience'],
-            
microsoft_graph_resource_id=_get_microsoft_graph_resource_id(arm_dict['name']), 
 # pylint: disable=line-too-long # change once microsoft_graph_resource_id is 
fixed in ARM
-            vm_image_alias_doc=arm_dict['vmImageAliasDoc'],  # pylint: 
disable=line-too-long
+            
microsoft_graph_resource_id=_get_microsoft_graph_resource_id(arm_dict['name']), 
 # change once microsoft_graph_resource_id is fixed in ARM
+            vm_image_alias_doc=arm_dict['vmImageAliasDoc'],
             media_resource_id=arm_dict['media'],
-            ossrdbms_resource_id=_get_ossrdbms_resource_id(arm_dict['name']),  
# pylint: disable=line-too-long # change once ossrdbms_resource_id is available 
via ARM
-            
active_directory_data_lake_resource_id=arm_dict['activeDirectoryDataLake'] if 
'activeDirectoryDataLake' in arm_dict else None,  # pylint: 
disable=line-too-long
-            app_insights_resource_id=arm_dict['appInsightsResourceId'] if 
'appInsightsResourceId' in arm_dict else None,
-            log_analytics_resource_id=arm_dict['logAnalyticsResourceId'] if 
'logAnalyticsResourceId' in arm_dict else None),  # pylint: 
disable=line-too-long
+            ossrdbms_resource_id=_get_ossrdbms_resource_id(arm_dict['name']),  
# change once ossrdbms_resource_id is available via ARM
+            
active_directory_data_lake_resource_id=arm_dict['activeDirectoryDataLake'] if 
'activeDirectoryDataLake' in arm_dict else None,
+            app_insights_resource_id=get_endpoint('appInsightsResourceId', 
fallback_value=_get_app_insights_resource_id(arm_dict['name'])),
+            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']))),
         suffixes=CloudSuffixes(
-            storage_endpoint=arm_dict['suffixes']['storage'],
-            
storage_sync_endpoint=arm_dict['suffix']['storageSyncEndpointSuffix'] if 
'storageSyncEndpointSuffix' in arm_dict['suffixes'] else 
_get_storage_sync_endpoint(arm_dict['name']),  # pylint: disable=line-too-long
-            keyvault_dns=arm_dict['suffixes']['keyVaultDns'],
-            sql_server_hostname=arm_dict['suffixes']['sqlServerHostname'],
-            mysql_server_endpoint=arm_dict['suffixes']['mysqlServerEndpoint'],
-            
postgresql_server_endpoint=arm_dict['suffixes']['postgresqlServerEndpoint'],
-            
mariadb_server_endpoint=arm_dict['suffixes']['mariadbServerEndpoint'],
-            
azure_datalake_store_file_system_endpoint=arm_dict['suffixes']['azureDataLakeStoreFileSystem']
 if 'azureDataLakeStoreFileSystem' in arm_dict['suffixes'] else None,  # 
pylint: disable=line-too-long
-            
azure_datalake_analytics_catalog_and_job_endpoint=arm_dict['suffixes']['azureDataLakeAnalyticsCatalogAndJob']
 if 'azureDataLakeAnalyticsCatalogAndJob' in arm_dict['suffixes'] else None,  # 
pylint: disable=line-too-long
-            acr_login_server_endpoint=arm_dict['suffixes']['acrLoginServer'] 
if 'acrLoginServer' in arm_dict['suffixes'] else None))  # pylint: 
disable=line-too-long
+            storage_endpoint=get_suffix('storage'),
+            storage_sync_endpoint=get_suffix('storageSyncEndpointSuffix', 
fallback_value=_get_storage_sync_endpoint(arm_dict['name'])),
+            keyvault_dns=get_suffix('keyVaultDns', add_dot=True),
+            sql_server_hostname=sql_server_hostname,
+            mysql_server_endpoint=get_suffix('mysqlServerEndpoint', 
add_dot=True, fallback_value=get_db_server_endpoint('.mysql')),
+            postgresql_server_endpoint=get_suffix('postgresqlServerEndpoint', 
add_dot=True, fallback_value=get_db_server_endpoint('.postgres')),
+            mariadb_server_endpoint=get_suffix('mariadbServerEndpoint', 
add_dot=True, fallback_value=get_db_server_endpoint('.mariadb')),
+            
azure_datalake_store_file_system_endpoint=get_suffix('azureDataLakeStoreFileSystem'),
+            
azure_datalake_analytics_catalog_and_job_endpoint=get_suffix('azureDataLakeAnalyticsCatalogAndJob'),
+            synapse_analytics_endpoint=get_suffix('synapseAnalytics', 
add_dot=True, fallback_value=_get_synapse_analytics_endpoint(arm_dict['name'])),
+            acr_login_server_endpoint=get_suffix('acrLoginServer', 
add_dot=True)))
 
 
-class Cloud(object):  # pylint: disable=too-few-public-methods
+class Cloud:  # pylint: disable=too-few-public-methods
     """ Represents an Azure Cloud instance """
 
     def __init__(self,
@@ -251,12 +332,13 @@
         active_directory_graph_resource_id='https://graph.windows.net/',
         microsoft_graph_resource_id='https://graph.microsoft.com/',
         active_directory_data_lake_resource_id='https://datalake.azure.net/',
-        
vm_image_alias_doc='https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/arm-compute/quickstart-templates/aliases.json',
  # pylint: disable=line-too-long
+        
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.azure.net',
         ossrdbms_resource_id='https://ossrdbms-aad.database.windows.net',
         app_insights_resource_id='https://api.applicationinsights.io',
         log_analytics_resource_id='https://api.loganalytics.io',
-        
app_insights_telemetry_channel_resource_id='https://dc.applicationinsights.azure.com/v2/track'),
+        
app_insights_telemetry_channel_resource_id='https://dc.applicationinsights.azure.com/v2/track',
+        synapse_analytics_resource_id='https://dev.azuresynapse.net'),
     suffixes=CloudSuffixes(
         storage_endpoint='core.windows.net',
         storage_sync_endpoint='afs.azure.net',
@@ -267,7 +349,8 @@
         mariadb_server_endpoint='.mariadb.database.azure.com',
         azure_datalake_store_file_system_endpoint='azuredatalakestore.net',
         
azure_datalake_analytics_catalog_and_job_endpoint='azuredatalakeanalytics.net',
-        acr_login_server_endpoint='.azurecr.io'))
+        acr_login_server_endpoint='.azurecr.io',
+        synapse_analytics_endpoint='.dev.azuresynapse.net'))
 
 AZURE_CHINA_CLOUD = Cloud(
     'AzureChinaCloud',
@@ -281,12 +364,13 @@
         
active_directory_resource_id='https://management.core.chinacloudapi.cn/',
         active_directory_graph_resource_id='https://graph.chinacloudapi.cn/',
         microsoft_graph_resource_id='https://microsoftgraph.chinacloudapi.cn',
-        
vm_image_alias_doc='https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/arm-compute/quickstart-templates/aliases.json',
  # pylint: disable=line-too-long
+        
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.chinacloudapi.cn',
         ossrdbms_resource_id='https://ossrdbms-aad.database.chinacloudapi.cn',
         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'),
+        
app_insights_telemetry_channel_resource_id='https://dc.applicationinsights.azure.cn/v2/track',
+        synapse_analytics_resource_id='https://dev.azuresynapse.net'),
     suffixes=CloudSuffixes(
         storage_endpoint='core.chinacloudapi.cn',
         keyvault_dns='.vault.azure.cn',
@@ -294,7 +378,8 @@
         mysql_server_endpoint='.mysql.database.chinacloudapi.cn',
         postgresql_server_endpoint='.postgres.database.chinacloudapi.cn',
         mariadb_server_endpoint='.mariadb.database.chinacloudapi.cn',
-        acr_login_server_endpoint='.azurecr.cn'))
+        acr_login_server_endpoint='.azurecr.cn',
+        synapse_analytics_endpoint='.dev.azuresynapse.azure.cn'))
 
 AZURE_US_GOV_CLOUD = Cloud(
     'AzureUSGovernment',
@@ -308,7 +393,7 @@
         
active_directory_resource_id='https://management.core.usgovcloudapi.net/',
         active_directory_graph_resource_id='https://graph.windows.net/',
         microsoft_graph_resource_id='https://graph.microsoft.us/',
-        
vm_image_alias_doc='https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/arm-compute/quickstart-templates/aliases.json',
  # pylint: disable=line-too-long
+        
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.usgovcloudapi.net',
         ossrdbms_resource_id='https://ossrdbms-aad.database.usgovcloudapi.net',
         app_insights_resource_id='https://api.applicationinsights.us',
@@ -336,7 +421,7 @@
         active_directory_resource_id='https://management.core.cloudapi.de/',
         active_directory_graph_resource_id='https://graph.cloudapi.de/',
         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',
  # pylint: disable=line-too-long
+        
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'),
     suffixes=CloudSuffixes(
@@ -354,7 +439,7 @@
         arm_cloud_dict = 
json.loads(urlretrieve(os.getenv('ARM_CLOUD_METADATA_URL')))
         cli_cloud_dict = _convert_arm_to_cli(arm_cloud_dict)
         if 'AzureCloud' in cli_cloud_dict:
-            cli_cloud_dict['AzureCloud'].endpoints.active_directory = 
'https://login.microsoftonline.com'  # pylint: disable=line-too-long # change 
once active_directory is fixed in ARM for the public cloud
+            cli_cloud_dict['AzureCloud'].endpoints.active_directory = 
'https://login.microsoftonline.com'  # change once active_directory is fixed in 
ARM for the public cloud
         KNOWN_CLOUDS = list(cli_cloud_dict.values())
     except Exception as ex:  # pylint: disable=broad-except
         logger.warning('Failed to load cloud metadata from the url specified 
by ARM_CLOUD_METADATA_URL')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-core-2.9.1/azure/cli/core/commands/__init__.py 
new/azure-cli-core-2.10.1/azure/cli/core/commands/__init__.py
--- old/azure-cli-core-2.9.1/azure/cli/core/commands/__init__.py        
2020-07-16 10:09:55.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure/cli/core/commands/__init__.py       
2020-08-06 10:46:59.000000000 +0200
@@ -118,7 +118,7 @@
 
 
 # pylint: disable=too-many-instance-attributes
-class CacheObject(object):
+class CacheObject:
 
     def path(self, args, kwargs):
         from azure.cli.core._environment import get_config_dir
@@ -349,7 +349,7 @@
                                    operation_group=operation_group)
 
     def update_context(self, obj_inst):
-        class UpdateContext(object):
+        class UpdateContext:
             def __init__(self, instance):
                 self.instance = instance
 
@@ -860,7 +860,7 @@
             pass
 
 
-class LongRunningOperation(object):  # pylint: disable=too-few-public-methods
+class LongRunningOperation:  # pylint: disable=too-few-public-methods
     def __init__(self, cli_ctx, start_msg='', finish_msg='', 
poller_done_interval_ms=1000.0):
 
         self.cli_ctx = cli_ctx
@@ -1048,7 +1048,7 @@
     return _load_command_loader(loader, args, mod, 
'azure.cli.command_modules.')
 
 
-class ExtensionCommandSource(object):
+class ExtensionCommandSource:
     """ Class for commands contributed by an extension """
 
     def __init__(self, overrides_command=False, extension_name=None, 
preview=False, experimental=False):
@@ -1129,7 +1129,7 @@
 
 
 # pylint: disable=too-few-public-methods
-class CliCommandType(object):
+class CliCommandType:
 
     def __init__(self, overrides=None, **kwargs):
         if isinstance(overrides, str):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.9.1/azure/cli/core/commands/arm.py 
new/azure-cli-core-2.10.1/azure/cli/core/commands/arm.py
--- old/azure-cli-core-2.9.1/azure/cli/core/commands/arm.py     2020-07-16 
10:09:55.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure/cli/core/commands/arm.py    2020-08-06 
10:46:59.000000000 +0200
@@ -31,7 +31,7 @@
 
 
 # pylint:disable=too-many-lines
-class ArmTemplateBuilder(object):
+class ArmTemplateBuilder:
 
     def __init__(self):
         template = OrderedDict()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-core-2.9.1/azure/cli/core/commands/client_factory.py 
new/azure-cli-core-2.10.1/azure/cli/core/commands/client_factory.py
--- old/azure-cli-core-2.9.1/azure/cli/core/commands/client_factory.py  
2020-07-16 10:09:55.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure/cli/core/commands/client_factory.py 
2020-08-06 10:46:59.000000000 +0200
@@ -174,7 +174,8 @@
 
 
 def get_data_service_client(cli_ctx, service_type, account_name, account_key, 
connection_string=None,
-                            sas_token=None, socket_timeout=None, 
token_credential=None, endpoint_suffix=None):
+                            sas_token=None, socket_timeout=None, 
token_credential=None, endpoint_suffix=None,
+                            location_mode=None):
     logger.debug('Getting data service client service_type=%s', 
service_type.__name__)
     try:
         client_kwargs = {'account_name': account_name,
@@ -188,6 +189,8 @@
         if endpoint_suffix:
             client_kwargs['endpoint_suffix'] = endpoint_suffix
         client = service_type(**client_kwargs)
+        if location_mode:
+            client.location_mode = location_mode
     except ValueError as exc:
         _ERROR_STORAGE_MISSING_INFO = get_sdk(cli_ctx, 
ResourceType.DATA_STORAGE,
                                               
'common._error#_ERROR_STORAGE_MISSING_INFO')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-core-2.9.1/azure/cli/core/commands/progress.py 
new/azure-cli-core-2.10.1/azure/cli/core/commands/progress.py
--- old/azure-cli-core-2.9.1/azure/cli/core/commands/progress.py        
2020-07-16 10:09:55.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure/cli/core/commands/progress.py       
2020-08-06 10:46:59.000000000 +0200
@@ -10,7 +10,7 @@
 BAR_LEN = 70
 
 
-class ProgressViewBase(object):
+class ProgressViewBase:
     """ a view base for progress reporting """
     def __init__(self, out):
         self.out = out
@@ -28,7 +28,7 @@
         pass  # pylint: disable=unnecessary-pass
 
 
-class ProgressReporter(object):
+class ProgressReporter:
     """ generic progress reporter """
     def __init__(self, message='', value=None, total_value=None):
         self.message = message
@@ -45,7 +45,7 @@
         total_val = kwargs.get('total_val', self.total_val)
         value = kwargs.get('value', self.value)
         if value and total_val:
-            assert value >= 0 and value <= total_val and total_val >= 0
+            assert 0 <= value <= total_val
             self.closed = value == total_val
         self.total_val = total_val
         self.value = value
@@ -57,7 +57,7 @@
         return {'message': self.message, 'percent': percent}
 
 
-class ProgressHook(object):
+class ProgressHook:
     """ sends the progress to the view """
     def __init__(self):
         self.reporter = ProgressReporter()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.9.1/azure/cli/core/decorators.py 
new/azure-cli-core-2.10.1/azure/cli/core/decorators.py
--- old/azure-cli-core-2.9.1/azure/cli/core/decorators.py       2020-07-16 
10:09:55.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure/cli/core/decorators.py      2020-08-06 
10:46:59.000000000 +0200
@@ -17,7 +17,7 @@
 
 
 # pylint: disable=too-few-public-methods
-class Completer(object):
+class Completer:
 
     def __init__(self, func):
         self.func = func
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-core-2.9.1/azure/cli/core/extension/__init__.py 
new/azure-cli-core-2.10.1/azure/cli/core/extension/__init__.py
--- old/azure-cli-core-2.9.1/azure/cli/core/extension/__init__.py       
2020-07-16 10:09:55.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure/cli/core/extension/__init__.py      
2020-08-06 10:46:59.000000000 +0200
@@ -8,12 +8,12 @@
 import traceback
 import json
 import re
-import pkginfo
-
-from azure.cli.core._config import GLOBAL_CONFIG_DIR, ENV_VAR_PREFIX
 from distutils.sysconfig import get_python_lib
+
+import pkginfo
 from knack.config import CLIConfig
 from knack.log import get_logger
+from azure.cli.core._config import GLOBAL_CONFIG_DIR, ENV_VAR_PREFIX
 
 az_config = CLIConfig(config_dir=GLOBAL_CONFIG_DIR, 
config_env_var_prefix=ENV_VAR_PREFIX)
 _CUSTOM_EXT_DIR = az_config.get('extension', 'dir', None)
@@ -51,7 +51,7 @@
         return "The extension {} is not installed.".format(self.extension_name)
 
 
-class Extension(object):
+class Extension:
 
     def __init__(self, name, ext_type, path=None):
         self.name = name
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-core-2.9.1/azure/cli/core/extension/_homebrew_patch.py 
new/azure-cli-core-2.10.1/azure/cli/core/extension/_homebrew_patch.py
--- old/azure-cli-core-2.9.1/azure/cli/core/extension/_homebrew_patch.py        
2020-07-16 10:09:55.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure/cli/core/extension/_homebrew_patch.py       
2020-08-06 10:46:59.000000000 +0200
@@ -18,7 +18,7 @@
 
 
 # A workaround for https://github.com/Azure/azure-cli/issues/4428
-class HomebrewPipPatch(object):  # pylint: disable=too-few-public-methods
+class HomebrewPipPatch:  # pylint: disable=too-few-public-methods
 
     CFG_FILE = os.path.expanduser(os.path.join('~', '.pydistutils.cfg'))
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-core-2.9.1/azure/cli/core/extension/operations.py 
new/azure-cli-core-2.10.1/azure/cli/core/extension/operations.py
--- old/azure-cli-core-2.9.1/azure/cli/core/extension/operations.py     
2020-07-16 10:09:55.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure/cli/core/extension/operations.py    
2020-08-06 10:46:59.000000000 +0200
@@ -85,8 +85,8 @@
     check_version_compatibility(azext_metadata)
 
 
-def _add_whl_ext(cmd, source, ext_sha256=None, pip_extra_index_urls=None, 
pip_proxy=None, system=None):  # pylint: disable=too-many-statements
-    cmd.cli_ctx.get_progress_controller().add(message='Analyzing')
+def _add_whl_ext(cli_ctx, source, ext_sha256=None, pip_extra_index_urls=None, 
pip_proxy=None, system=None):  # pylint: disable=too-many-statements
+    cli_ctx.get_progress_controller().add(message='Analyzing')
     if not source.endswith('.whl'):
         raise ValueError('Unknown extension type. Only Python wheels are 
supported.')
     url_parse_result = urlparse(source)
@@ -108,7 +108,7 @@
         logger.debug('Downloading %s to %s', source, ext_file)
         import requests
         try:
-            cmd.cli_ctx.get_progress_controller().add(message='Downloading')
+            cli_ctx.get_progress_controller().add(message='Downloading')
             _whl_download_from_url(url_parse_result, ext_file)
         except (requests.exceptions.ConnectionError, 
requests.exceptions.HTTPError) as err:
             raise CLIError('Please ensure you have network connection. Error 
detail: {}'.format(str(err)))
@@ -130,7 +130,7 @@
             raise CLIError("The checksum of the extension does not match the 
expected value. "
                            "Use --debug for more information.")
     try:
-        cmd.cli_ctx.get_progress_controller().add(message='Validating')
+        cli_ctx.get_progress_controller().add(message='Validating')
         _validate_whl_extension(ext_file)
     except AssertionError:
         logger.debug(traceback.format_exc())
@@ -140,7 +140,7 @@
     logger.debug('Validation successful on %s', ext_file)
     # Check for distro consistency
     check_distro_consistency()
-    cmd.cli_ctx.get_progress_controller().add(message='Installing')
+    cli_ctx.get_progress_controller().add(message='Installing')
     # Install with pip
     extension_path = build_extension_path(extension_name, system)
     pip_args = ['install', '--target', extension_path, ext_file]
@@ -206,15 +206,15 @@
         raise CLIError(min_max_msg_fmt)
 
 
-def add_extension(cmd, source=None, extension_name=None, index_url=None, 
yes=None,  # pylint: disable=unused-argument
+def add_extension(cmd=None, source=None, extension_name=None, index_url=None, 
yes=None,  # pylint: disable=unused-argument
                   pip_extra_index_urls=None, pip_proxy=None, system=None,
-                  version=None):
+                  version=None, cli_ctx=None):
     ext_sha256 = None
 
     version = None if version == 'latest' else version
-
+    cmd_cli_ctx = cli_ctx or cmd.cli_ctx
     if extension_name:
-        cmd.cli_ctx.get_progress_controller().add(message='Searching')
+        cmd_cli_ctx.get_progress_controller().add(message='Searching')
         ext = None
         try:
             ext = get_extension(extension_name)
@@ -236,7 +236,7 @@
                 err = "No matching extensions for '{}'. Use --debug for more 
information.".format(extension_name)
             raise CLIError(err)
 
-    extension_name = _add_whl_ext(cmd=cmd, source=source, 
ext_sha256=ext_sha256,
+    extension_name = _add_whl_ext(cli_ctx=cmd_cli_ctx, source=source, 
ext_sha256=ext_sha256,
                                   pip_extra_index_urls=pip_extra_index_urls, 
pip_proxy=pip_proxy, system=system)
     try:
         ext = get_extension(extension_name)
@@ -289,8 +289,9 @@
         raise CLIError(e)
 
 
-def update_extension(cmd, extension_name, index_url=None, 
pip_extra_index_urls=None, pip_proxy=None):
+def update_extension(cmd=None, extension_name=None, index_url=None, 
pip_extra_index_urls=None, pip_proxy=None, cli_ctx=None):
     try:
+        cmd_cli_ctx = cli_ctx or cmd.cli_ctx
         ext = get_extension(extension_name, ext_type=WheelExtension)
         cur_version = ext.get_version()
         try:
@@ -307,7 +308,7 @@
         shutil.rmtree(extension_path)
         # Install newer version
         try:
-            _add_whl_ext(cmd=cmd, source=download_url, ext_sha256=ext_sha256,
+            _add_whl_ext(cli_ctx=cmd_cli_ctx, source=download_url, 
ext_sha256=ext_sha256,
                          pip_extra_index_urls=pip_extra_index_urls, 
pip_proxy=pip_proxy)
             logger.debug('Deleting backup of old extension at %s', backup_dir)
             shutil.rmtree(backup_dir)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.9.1/azure/cli/core/local_context.py 
new/azure-cli-core-2.10.1/azure/cli/core/local_context.py
--- old/azure-cli-core-2.9.1/azure/cli/core/local_context.py    2020-07-16 
10:09:55.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure/cli/core/local_context.py   2020-08-06 
10:46:59.000000000 +0200
@@ -33,7 +33,7 @@
     return None
 
 
-class AzCLILocalContext(object):  # pylint: 
disable=too-many-instance-attributes
+class AzCLILocalContext:  # pylint: disable=too-many-instance-attributes
 
     def __init__(self, cli_ctx):
         self.cli_ctx = cli_ctx
@@ -180,7 +180,7 @@
         return result
 
 
-class LocalContextAttribute(object):
+class LocalContextAttribute:
     # pylint: disable=too-few-public-methods
     def __init__(self, name, actions, scopes=None):
         """ Local Context Attribute arguments
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.9.1/azure/cli/core/parser.py 
new/azure-cli-core-2.10.1/azure/cli/core/parser.py
--- old/azure-cli-core-2.9.1/azure/cli/core/parser.py   2020-07-16 
10:09:55.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure/cli/core/parser.py  2020-08-06 
10:46:59.000000000 +0200
@@ -280,37 +280,167 @@
         self._namespace, self._raw_arguments = 
super().parse_known_args(args=args, namespace=namespace)
         return self._namespace, self._raw_arguments
 
-    def _check_value(self, action, value):
+    def _get_extension_command_tree(self):
+        from azure.cli.core._session import EXT_CMD_TREE
+        import os
+        VALID_SECOND = 3600 * 24 * 10
+        # self.cli_ctx is None when self.prog is beyond 'az', such as 'az iot'.
+        # use cli_ctx from cli_help which is not lost.
+        cli_ctx = self.cli_ctx or (self.cli_help.cli_ctx if self.cli_help else 
None)
+        if not cli_ctx:
+            return None
+        EXT_CMD_TREE.load(os.path.join(cli_ctx.config.config_dir, 
'extensionCommandTree.json'), VALID_SECOND)
+        if not EXT_CMD_TREE.data:
+            import requests
+            from azure.cli.core.util import should_disable_connection_verify
+            try:
+                response = requests.get(
+                    
'https://azurecliextensionsync.blob.core.windows.net/cmd-index/extensionCommandTree.json',
+                    verify=(not should_disable_connection_verify()),
+                    timeout=300)
+            except Exception as ex:  # pylint: disable=broad-except
+                logger.info("Request failed for extension command tree: %s", 
str(ex))
+                return None
+            if response.status_code == 200:
+                EXT_CMD_TREE.data = response.json()
+                EXT_CMD_TREE.save_with_retry()
+            else:
+                logger.info("Error when retrieving extension command tree. 
Response code: %s", response.status_code)
+                return None
+        return EXT_CMD_TREE
+
+    def _search_in_extension_commands(self, command_str):
+        """Search the command in an extension commands dict which mimics a 
prefix tree.
+        If the value of the dict item is a string, then the key represents the 
end of a complete command
+        and the value is the name of the extension that the command belongs to.
+        An example of the dict read from extensionCommandTree.json:
+        {
+            "aks": {
+                "create": "aks-preview",
+                "update": "aks-preview",
+                "app": {
+                    "up": "deploy-to-azure"
+                },
+                "use-dev-spaces": "dev-spaces"
+            },
+            ...
+        }
+        """
+
+        cmd_chain = self._get_extension_command_tree()
+        for part in command_str.split():
+            try:
+                if isinstance(cmd_chain[part], str):
+                    return cmd_chain[part]
+                cmd_chain = cmd_chain[part]
+            except KeyError:
+                return None
+        return None
+
+    def _get_extension_use_dynamic_install_config(self):
+        cli_ctx = self.cli_ctx or (self.cli_help.cli_ctx if self.cli_help else 
None)
+        use_dynamic_install = cli_ctx.config.get(
+            'extension', 'use_dynamic_install', 'no').lower() if cli_ctx else 
'no'
+        if use_dynamic_install not in ['no', 'yes_prompt', 
'yes_without_prompt']:
+            use_dynamic_install = 'no'
+        return use_dynamic_install
+
+    def _check_value(self, action, value):  # pylint: 
disable=too-many-statements, too-many-locals
         # Override to customize the error message when a argument is not among 
the available choices
         # converted value must be one of the choices (if specified)
-        if action.choices is not None and value not in action.choices:
+        if action.choices is not None and value not in action.choices:  # 
pylint: disable=too-many-nested-blocks
+            caused_by_extension_not_installed = False
             if not self.command_source:
-                # parser has no `command_source`, value is part of command 
itself
-                extensions_link = 
'https://docs.microsoft.com/en-us/cli/azure/azure-cli-extensions-overview'
-                error_msg = ("{prog}: '{value}' is not in the '{prog}' command 
group. See '{prog} --help'. "
-                             "If the command is from an extension, "
-                             "please make sure the corresponding extension is 
installed. "
-                             "To learn more about extensions, please visit "
-                             "{extensions_link}").format(prog=self.prog, 
value=value, extensions_link=extensions_link)
+                candidates = difflib.get_close_matches(value, action.choices, 
cutoff=0.7)
+                error_msg = None
+                # self.cli_ctx is None when self.prog is beyond 'az', such as 
'az iot'.
+                # use cli_ctx from cli_help which is not lost.
+                cli_ctx = self.cli_ctx or (self.cli_help.cli_ctx if 
self.cli_help else None)
+                use_dynamic_install = 
self._get_extension_use_dynamic_install_config()
+                if use_dynamic_install != 'no' and not candidates:
+                    # Check if the command is from an extension
+                    from azure.cli.core.util import roughly_parse_command
+                    cmd_list = self.prog.split() + self._raw_arguments
+                    command_str = roughly_parse_command(cmd_list[1:])
+                    ext_name = self._search_in_extension_commands(command_str)
+                    if ext_name:
+                        caused_by_extension_not_installed = True
+                        telemetry.set_command_details(command_str,
+                                                      
parameters=AzCliCommandInvoker._extract_parameter_names(cmd_list),  # pylint: 
disable=protected-access
+                                                      extension_name=ext_name)
+                        run_after_extension_installed = 
cli_ctx.config.getboolean('extension',
+                                                                               
   'run_after_dynamic_install',
+                                                                               
   False) if cli_ctx else False
+                        if use_dynamic_install == 'yes_without_prompt':
+                            logger.warning('The command requires the extension 
%s. '
+                                           'It will be installed first.', 
ext_name)
+                            go_on = True
+                        else:
+                            from knack.prompting import prompt_y_n, 
NoTTYException
+                            prompt_msg = 'The command requires the extension 
{}. ' \
+                                'Do you want to install it 
now?'.format(ext_name)
+                            if run_after_extension_installed:
+                                prompt_msg = '{} The command will continue to 
run after the extension is installed.' \
+                                    .format(prompt_msg)
+                            NO_PROMPT_CONFIG_MSG = "Run 'az config set 
extension.use_dynamic_install=" \
+                                "yes_without_prompt' to allow installing 
extensions without prompt."
+                            try:
+                                go_on = prompt_y_n(prompt_msg, default='y')
+                                if go_on:
+                                    logger.warning(NO_PROMPT_CONFIG_MSG)
+                            except NoTTYException:
+                                logger.warning("The command requires the 
extension %s.\n "
+                                               "Unable to prompt for extension 
install confirmation as no tty "
+                                               "available. %s", ext_name, 
NO_PROMPT_CONFIG_MSG)
+                                go_on = False
+                        if go_on:
+                            from azure.cli.core.extension.operations import 
add_extension
+                            add_extension(cli_ctx=cli_ctx, 
extension_name=ext_name)
+                            if run_after_extension_installed:
+                                import subprocess
+                                import platform
+                                exit_code = subprocess.call(cmd_list, 
shell=platform.system() == 'Windows')
+                                telemetry.set_user_fault("Extension {} 
dynamically installed and commands will be "
+                                                         "rerun 
automatically.".format(ext_name))
+                                self.exit(exit_code)
+                            else:
+                                error_msg = 'Extension {} installed. Please 
rerun your command.'.format(ext_name)
+                        else:
+                            error_msg = "The command requires the extension 
{ext_name}. " \
+                                "To install, run 'az extension add -n 
{ext_name}'.".format(ext_name=ext_name)
+                if not error_msg:
+                    # parser has no `command_source`, value is part of command 
itself
+                    error_msg = "{prog}: '{value}' is not in the '{prog}' 
command group. See '{prog} --help'." \
+                        .format(prog=self.prog, value=value)
+                    if use_dynamic_install.lower() == 'no':
+                        extensions_link = 
'https://docs.microsoft.com/en-us/cli/azure/azure-cli-extensions-overview'
+                        error_msg = ("{msg} "
+                                     "If the command is from an extension, "
+                                     "please make sure the corresponding 
extension is installed. "
+                                     "To learn more about extensions, please 
visit "
+                                     
"{extensions_link}").format(msg=error_msg, extensions_link=extensions_link)
             else:
                 # `command_source` indicates command values have been parsed, 
value is an argument
                 parameter = action.option_strings[0] if action.option_strings 
else action.dest
                 error_msg = "{prog}: '{value}' is not a valid value for 
'{param}'. See '{prog} --help'.".format(
                     prog=self.prog, value=value, param=parameter)
+                candidates = difflib.get_close_matches(value, action.choices, 
cutoff=0.7)
+
             telemetry.set_user_fault(error_msg)
             with CommandLoggerContext(logger):
                 logger.error(error_msg)
-            candidates = difflib.get_close_matches(value, action.choices, 
cutoff=0.7)
-            if candidates:
-                print_args = {
-                    's': 's' if len(candidates) > 1 else '',
-                    'verb': 'are' if len(candidates) > 1 else 'is',
-                    'value': value
-                }
-                self._suggestion_msg.append("\nThe most similar choice{s} to 
'{value}' {verb}:".format(**print_args))
-                self._suggestion_msg.append('\n'.join(['\t' + candidate for 
candidate in candidates]))
-
-            failure_recovery_recommendations = 
self._get_failure_recovery_recommendations(action)
-            self._suggestion_msg.extend(failure_recovery_recommendations)
-            self._print_suggestion_msg(sys.stderr)
+            if not caused_by_extension_not_installed:
+                if candidates:
+                    print_args = {
+                        's': 's' if len(candidates) > 1 else '',
+                        'verb': 'are' if len(candidates) > 1 else 'is',
+                        'value': value
+                    }
+                    self._suggestion_msg.append("\nThe most similar choice{s} 
to '{value}' {verb}:"
+                                                .format(**print_args))
+                    self._suggestion_msg.append('\n'.join(['\t' + candidate 
for candidate in candidates]))
+
+                failure_recovery_recommendations = 
self._get_failure_recovery_recommendations(action)
+                self._suggestion_msg.extend(failure_recovery_recommendations)
+                self._print_suggestion_msg(sys.stderr)
             self.exit(2)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-core-2.9.1/azure/cli/core/profiles/_shared.py 
new/azure-cli-core-2.10.1/azure/cli/core/profiles/_shared.py
--- old/azure-cli-core-2.9.1/azure/cli/core/profiles/_shared.py 2020-07-16 
10:09:55.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure/cli/core/profiles/_shared.py        
2020-08-06 10:46:59.000000000 +0200
@@ -24,7 +24,7 @@
 PROFILE_TYPE = object()
 
 
-class CustomResourceType(object):  # pylint: disable=too-few-public-methods
+class CustomResourceType:  # pylint: disable=too-few-public-methods
     def __init__(self, import_prefix, client_name):
         self.import_prefix = import_prefix
         self.client_name = client_name
@@ -111,7 +111,7 @@
         self.client_name = client_name
 
 
-class SDKProfile(object):  # pylint: disable=too-few-public-methods
+class SDKProfile:  # pylint: disable=too-few-public-methods
 
     def __init__(self, default_api_version, profile=None):
         """Constructor.
@@ -136,7 +136,8 @@
             'resource_skus': '2019-04-01',
             'disks': '2020-05-01',
             'disk_encryption_sets': '2020-05-01',
-            'snapshots': '2019-07-01',
+            'disk_accesses': '2020-05-01',
+            'snapshots': '2020-05-01',
             'galleries': '2019-12-01',
             'gallery_images': '2019-12-01',
             'gallery_image_versions': '2019-12-01',
@@ -146,7 +147,7 @@
         ResourceType.MGMT_RESOURCE_LINKS: '2016-09-01',
         ResourceType.MGMT_RESOURCE_LOCKS: '2016-09-01',
         ResourceType.MGMT_RESOURCE_POLICY: '2019-09-01',
-        ResourceType.MGMT_RESOURCE_RESOURCES: '2019-07-01',
+        ResourceType.MGMT_RESOURCE_RESOURCES: '2020-06-01',
         ResourceType.MGMT_RESOURCE_SUBSCRIPTIONS: '2019-11-01',
         ResourceType.MGMT_RESOURCE_DEPLOYMENTSCRIPTS: '2019-10-01-preview',
         ResourceType.MGMT_NETWORK_DNS: '2018-05-01',
@@ -281,7 +282,7 @@
 }
 
 
-class _ApiVersions(object):  # pylint: disable=too-few-public-methods
+class _ApiVersions:  # pylint: disable=too-few-public-methods
     def __init__(self, client_type, sdk_profile, post_process):
         self._client_type = client_type
         self._sdk_profile = sdk_profile
@@ -342,7 +343,7 @@
 
 
 @total_ordering
-class _SemVerAPIFormat(object):
+class _SemVerAPIFormat:
     """Basic semver x.y.z API format.
     Supports x, or x.y, or x.y.z
     """
@@ -366,7 +367,7 @@
 
 
 @total_ordering  # pylint: disable=too-few-public-methods
-class _DateAPIFormat(object):
+class _DateAPIFormat:
     """ Class to support comparisons for API versions in
         YYYY-MM-DD, YYYY-MM-DD-preview, YYYY-MM-DD-profile, 
YYYY-MM-DD-profile-preview
         or any string that starts with YYYY-MM-DD format. A special case is 
made for 'latest'.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.9.1/azure/cli/core/telemetry.py 
new/azure-cli-core-2.10.1/azure/cli/core/telemetry.py
--- old/azure-cli-core-2.9.1/azure/cli/core/telemetry.py        2020-07-16 
10:09:55.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure/cli/core/telemetry.py       2020-08-06 
10:46:59.000000000 +0200
@@ -24,7 +24,7 @@
 CORRELATION_ID_PROP_NAME = 'Reserved.DataModel.CorrelationId'
 
 
-class TelemetrySession(object):  # pylint: disable=too-many-instance-attributes
+class TelemetrySession:  # pylint: disable=too-many-instance-attributes
     def __init__(self, correlation_id=None, application=None):
         self.start_time = None
         self.end_time = None
@@ -45,6 +45,8 @@
         self.extension_management_detail = None
         self.raw_command = None
         self.mode = 'default'
+        self.init_time_elapsed = None
+        self.invoke_time_elapsed = None
         # A dictionary with the application insight instrumentation key
         # as the key and an array of telemetry events as value
         self.events = defaultdict(list)
@@ -164,6 +166,8 @@
                               lambda: 
'{},{}'.format(locale.getdefaultlocale()[0], locale.getdefaultlocale()[1]))
         set_custom_properties(result, 'StartTime', str(self.start_time))
         set_custom_properties(result, 'EndTime', str(self.end_time))
+        set_custom_properties(result, 'InitTimeElapsed', 
str(self.init_time_elapsed))
+        set_custom_properties(result, 'InvokeTimeElapsed', 
str(self.invoke_time_elapsed))
         set_custom_properties(result, 'OutputType', self.output_type)
         set_custom_properties(result, 'RawCommand', self.raw_command)
         set_custom_properties(result, 'Params', ','.join(self.parameters or 
[]))
@@ -227,6 +231,16 @@
     _session.start_time = datetime.datetime.utcnow()
 
 
+@decorators.suppress_all_exceptions()
+def set_init_time_elapsed(init_time_elapsed):
+    _session.init_time_elapsed = init_time_elapsed
+
+
+@decorators.suppress_all_exceptions()
+def set_invoke_time_elapsed(invoke_time_elapsed):
+    _session.invoke_time_elapsed = invoke_time_elapsed
+
+
 @_user_agrees_to_telemetry
 @decorators.suppress_all_exceptions()
 def flush():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.9.1/azure/cli/core/util.py 
new/azure-cli-core-2.10.1/azure/cli/core/util.py
--- old/azure-cli-core-2.9.1/azure/cli/core/util.py     2020-07-16 
10:09:55.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure/cli/core/util.py    2020-08-06 
10:46:59.000000000 +0200
@@ -12,10 +12,10 @@
 import binascii
 import platform
 import ssl
-import six
 import re
 import logging
 
+import six
 from six.moves.urllib.request import urlopen  # pylint: disable=import-error
 from knack.log import get_logger
 from knack.util import CLIError, to_snake_case
@@ -50,6 +50,15 @@
 _VERSION_CHECK_TIME = 'check_time'
 _VERSION_UPDATE_TIME = 'update_time'
 
+# A list of reserved names that cannot be used as admin username of VM
+DISALLOWED_USER_NAMES = [
+    "administrator", "admin", "user", "user1", "test", "user2",
+    "test1", "user3", "admin1", "1", "123", "a", "actuser", "adm",
+    "admin2", "aspnet", "backup", "console", "guest",
+    "owner", "root", "server", "sql", "support", "support_388945a0",
+    "sys", "test2", "test3", "user4", "user5"
+]
+
 
 def handle_exception(ex):  # pylint: disable=too-many-return-statements
     # For error code, follow guidelines at 
https://docs.python.org/2/library/sys.html#sys.exit,
@@ -596,9 +605,13 @@
 
 def get_default_admin_username():
     try:
-        return getpass.getuser()
+        username = getpass.getuser()
     except KeyError:
-        return None
+        username = None
+    if username is None or username.lower() in DISALLOWED_USER_NAMES:
+        logger.warning('Default username %s is a reserved username. Use 
azureuser instead.', username)
+        username = 'azureuser'
+    return username
 
 
 def _find_child(parent, *args, **kwargs):
@@ -882,7 +895,7 @@
         return response
 
 
-class ConfiguredDefaultSetter(object):
+class ScopedConfig:
 
     def __init__(self, cli_config, use_local_config=None):
         self.use_local_config = use_local_config
@@ -899,6 +912,9 @@
         setattr(self.cli_config, 'use_local_config', 
self.original_use_local_config)
 
 
+ConfiguredDefaultSetter = ScopedConfig
+
+
 def _ssl_context():
     if sys.version_info < (3, 4) or (in_cloud_console() and platform.system() 
== 'Windows'):
         try:
@@ -998,3 +1014,25 @@
             release_info[k.lower()] = v.strip('"')
 
     return release_info.get('name', None), release_info.get('version_id', None)
+
+
+def roughly_parse_command(args):
+    # Roughly parse the command part: <az vm create> --name vm1
+    # Similar to knack.invocation.CommandInvoker._rudimentary_get_command, but 
we don't need to bother with
+    # positional args
+    nouns = []
+    for arg in args:
+        if arg and arg[0] != '-':
+            nouns.append(arg)
+        else:
+            break
+    return ' '.join(nouns).lower()
+
+
+def is_guid(guid):
+    import uuid
+    try:
+        uuid.UUID(guid)
+        return True
+    except ValueError:
+        return False
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-core-2.9.1/azure_cli_core.egg-info/PKG-INFO 
new/azure-cli-core-2.10.1/azure_cli_core.egg-info/PKG-INFO
--- old/azure-cli-core-2.9.1/azure_cli_core.egg-info/PKG-INFO   2020-07-16 
10:10:07.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure_cli_core.egg-info/PKG-INFO  2020-08-06 
10:47:07.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: azure-cli-core
-Version: 2.9.1
+Version: 2.10.1
 Summary: Microsoft Azure Command-Line Tools Core Module
 Home-page: https://github.com/Azure/azure-cli
 Author: Microsoft Corporation
@@ -15,6 +15,14 @@
         Release History
         ===============
         
+        2.10.1
+        ++++++
+        * Minor fixes
+        
+        2.10.0
+        ++++++
+        * Minor fixes
+        
         2.9.1
         ++++++
         * Minor fixes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-core-2.9.1/azure_cli_core.egg-info/requires.txt 
new/azure-cli-core-2.10.1/azure_cli_core.egg-info/requires.txt
--- old/azure-cli-core-2.9.1/azure_cli_core.egg-info/requires.txt       
2020-07-16 10:10:07.000000000 +0200
+++ new/azure-cli-core-2.10.1/azure_cli_core.egg-info/requires.txt      
2020-08-06 10:47:07.000000000 +0200
@@ -4,7 +4,7 @@
 colorama~=0.4.1
 humanfriendly<9.0,>=4.7
 jmespath
-knack==0.7.1
+knack==0.7.2
 msal~=1.0.0
 msal-extensions~=0.1.3
 msrest>=0.4.4
@@ -15,7 +15,7 @@
 requests~=2.22
 six~=1.12
 pkginfo>=1.5.0.1
-azure-mgmt-resource==10.0.0
+azure-mgmt-resource==10.1.0
 azure-mgmt-core==1.0.0
 
 [:python_version<"3.0"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.9.1/setup.py 
new/azure-cli-core-2.10.1/setup.py
--- old/azure-cli-core-2.9.1/setup.py   2020-07-16 10:09:55.000000000 +0200
+++ new/azure-cli-core-2.10.1/setup.py  2020-08-06 10:46:59.000000000 +0200
@@ -17,7 +17,7 @@
     logger.warn("Wheel is not available, disabling bdist_wheel hook")
     cmdclass = {}
 
-VERSION = "2.9.1"
+VERSION = "2.10.1"
 # If we have source, validate that our version numbers match
 # This should prevent uploading releases with mismatched versions.
 try:
@@ -56,7 +56,7 @@
     'colorama~=0.4.1',
     'humanfriendly>=4.7,<9.0',
     'jmespath',
-    'knack==0.7.1',
+    'knack==0.7.2',
     'msal~=1.0.0',
     'msal-extensions~=0.1.3',
     'msrest>=0.4.4',
@@ -67,7 +67,7 @@
     'requests~=2.22',
     'six~=1.12',
     'pkginfo>=1.5.0.1',
-    'azure-mgmt-resource==10.0.0',
+    'azure-mgmt-resource==10.1.0',
     'azure-mgmt-core==1.0.0'
 ]
 


Reply via email to