Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/dev2' into nasc/indexTuning1111
Browse files Browse the repository at this point in the history
  • Loading branch information
nasc17 committed Nov 12, 2024
2 parents 437235f + b1f35f2 commit 74382dd
Show file tree
Hide file tree
Showing 115 changed files with 203,070 additions and 144,514 deletions.
8 changes: 8 additions & 0 deletions linter_exclusions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,14 @@ appconfig update:
encryption_key_version:
rule_exclusions:
- option_length_too_long
enable_arm_private_network_access:
rule_exclusions:
- option_length_too_long
appconfig create:
parameters:
enable_arm_private_network_access:
rule_exclusions:
- option_length_too_long
appservice ase create:
parameters:
force_network_security_group:
Expand Down
2 changes: 1 addition & 1 deletion src/azure-cli-core/azure/cli/core/breaking_change.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

logger = get_logger()

NEXT_BREAKING_CHANGE_RELEASE = '2.67.0'
NEXT_BREAKING_CHANGE_RELEASE = '2.73.0'
DEFAULT_BREAKING_CHANGE_TAG = '[Breaking Change]'


Expand Down
6 changes: 6 additions & 0 deletions src/azure-cli-core/azure/cli/core/extension/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,3 +380,9 @@ def is_stable_from_metadata(item):
return not (item["metadata"].get(EXT_METADATA_ISPREVIEW, False) or
item["metadata"].get(EXT_METADATA_ISEXPERIMENTAL, False) or
is_preview_from_semantic_version(item["metadata"]['version']))


def is_preview_from_metadata(item):
return bool(item["metadata"].get(EXT_METADATA_ISPREVIEW, False) or
item["metadata"].get(EXT_METADATA_ISEXPERIMENTAL, False) or
is_preview_from_semantic_version(item["metadata"]['version']))
27 changes: 25 additions & 2 deletions src/azure-cli-core/azure/cli/core/extension/_resolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from packaging.version import parse
from typing import Callable, List, NamedTuple, Union

from azure.cli.core.extension import ext_compat_with_cli, WHEEL_INFO_RE, is_stable_from_metadata
from azure.cli.core.extension import (ext_compat_with_cli, WHEEL_INFO_RE,
is_stable_from_metadata, is_preview_from_metadata)
from azure.cli.core.extension._index import get_index_extensions

from knack.log import get_logger
Expand Down Expand Up @@ -104,6 +105,28 @@ def resolve_from_index(extension_name, cur_version=None, index_url=None, target_
if not candidates:
raise NoExtensionCandidatesError(f"No extension found with name '{extension_name}'")

if allow_preview is None:
# default value of allow-preview changed from true to false
# and the following part deals with two influenced scenariors if user does not specify allow-preview
# 1. if extension module does not have any stable version, set allow-preview=True and display warning message to
# unblock those extension module user
# 2. if extension module has a later preview version than stable one, dispaly a warning message to user
# indicating how to try the newer preview one, but allow-preview is still set to be False by default
allow_preview = False
stable_candidates = list(filter(is_stable_from_metadata, candidates))
preview_candidates = list(filter(is_preview_from_metadata, candidates))
if len(stable_candidates) == 0:
logger.warning("No stable version of '%s' to install. Preview versions allowed.", extension_name)
allow_preview = True
elif len(preview_candidates) != 0:
max_preview_item = max(preview_candidates, key=lambda x: parse(x['metadata']['version']))
max_stable_item = max(stable_candidates, key=lambda x: parse(x['metadata']['version']))
if parse(max_preview_item['metadata']['version']) > parse(max_stable_item['metadata']['version']):
logger.warning("Extension '%s' has a later preview version to install, add `--allow-preview True` "
"to try preview version.", extension_name)
else:
logger.info("No preview versions need to be tried.")

# Helper to curry predicate functions
def list_filter(f):
return lambda cs: list(filter(f, cs))
Expand All @@ -120,7 +143,7 @@ def list_filter(f):
_ExtensionFilter(
filter=list_filter(is_stable_from_metadata),
on_empty_results_message=f"No suitable stable version of '{extension_name}' to install. "
f"Add `--allow-preview` to try preview versions"
f"Add `--allow-preview True` to try preview versions"
)]

if target_version:
Expand Down
18 changes: 9 additions & 9 deletions src/azure-cli-core/azure/cli/core/extension/dynamic_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,15 +110,15 @@ def _get_extension_run_after_dynamic_install_config(cli_ctx):


def _get_extension_allow_preview_install_config(cli_ctx):
default_value = True
if cli_ctx and cli_ctx.config.get('extension', 'dynamic_install_allow_preview', None) is None:
logger.warning("Preview version of extension is enabled by default for extension installation now. "
"Will be disabled in future release. ")
logger.warning("Please run 'az config set extension.dynamic_install_allow_preview=true or false' "
"to config it specifically. ")
dynamic_install_allow_preview = cli_ctx.config.getboolean('extension',
'dynamic_install_allow_preview',
default_value) if cli_ctx else default_value
dynamic_install_allow_preview = None
if cli_ctx:
if cli_ctx.config.get('extension', 'dynamic_install_allow_preview', None) is None:
logger.warning("Preview version of extension is disabled by default for extension installation, "
"enabled for modules without stable versions. ")
logger.warning("Please run 'az config set extension.dynamic_install_allow_preview=true or false' "
"to config it specifically. ")
else:
dynamic_install_allow_preview = cli_ctx.config.getboolean('extension', 'dynamic_install_allow_preview')
return dynamic_install_allow_preview


Expand Down
12 changes: 0 additions & 12 deletions src/azure-cli-core/azure/cli/core/extension/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,12 +306,6 @@ def check_version_compatibility(azext_metadata):
def add_extension(cmd=None, source=None, extension_name=None, index_url=None, yes=None, # pylint: disable=unused-argument, too-many-statements
pip_extra_index_urls=None, pip_proxy=None, system=None,
version=None, cli_ctx=None, upgrade=None, allow_preview=None):
if allow_preview is None:
logger.warning("Default enabled including preview versions for extension installation now. "
"Disabled in future release. "
"Use '--allow-preview true' to enable it specifically if needed. "
"Use '--allow-preview false' to install stable version only. ")
allow_preview = True
ext_sha256 = None
update_to_latest = version == 'latest' and not source

Expand Down Expand Up @@ -405,12 +399,6 @@ def show_extension(extension_name):


def update_extension(cmd=None, extension_name=None, index_url=None, pip_extra_index_urls=None, pip_proxy=None, allow_preview=None, cli_ctx=None, version=None, download_url=None, ext_sha256=None):
if allow_preview is None:
logger.warning("Default enabled including preview versions for extension installation now. "
"Disabled in future release. "
"Use '--allow-preview true' to enable it specifically if needed. "
"Use '--allow-preview false' to install stable version only. ")
allow_preview = True
try:
cmd_cli_ctx = cli_ctx or cmd.cli_ctx
ext = get_extension(extension_name, ext_type=WheelExtension)
Expand Down
50 changes: 41 additions & 9 deletions src/azure-cli-core/azure/cli/core/tests/test_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,15 +323,9 @@ def test_add_list_show_preview_extension(self):
self.assertEqual(ext["version"], "2.0.0a1")
remove_extension("ml")

def test_add_preview_extension_by_default(self):
def test_add_stable_extension_by_default(self):
test_ext_source = _get_test_data_file('extension_test_pkg-1.2.3-py3-none-any.whl')
with mock.patch('azure.cli.core.extension.operations.logger') as mock_logger:
add_extension(cmd=self.cmd, source=test_ext_source)
call_args = mock_logger.warning.call_args
self.assertEqual("Default enabled including preview versions for extension installation now. "
"Disabled in future release. "
"Use '--allow-preview true' to enable it specifically if needed. "
"Use '--allow-preview false' to install stable version only. ", call_args[0][0])
add_extension(cmd=self.cmd, source=test_ext_source)
ext = show_extension("extension-test-pkg")
self.assertEqual(ext["name"], "extension-test-pkg")
self.assertEqual(ext["version"], "1.2.3")
Expand Down Expand Up @@ -395,9 +389,47 @@ def test_add_extension_preview_inavailable(self):
from knack.util import CLIError
with mock.patch('azure.cli.core.extension._resolve.get_index_extensions',
return_value=mocked_index_data):
with self.assertRaisesRegex(CLIError, "No suitable stable version of 'extension-test-pkg' to install. Add `--allow-preview` to try preview versions"):
with self.assertRaisesRegex(CLIError, "No suitable stable version of 'extension-test-pkg' to install. Add `--allow-preview True` to try preview versions"):
add_extension(cmd=self.cmd, extension_name=extension_name, allow_preview=False)

with mock.patch('azure.cli.core.extension._resolve.logger') as mock_logger:
add_extension(cmd=self.cmd, extension_name=extension_name)
call_args = mock_logger.warning.call_args
self.assertEqual("No stable version of '%s' to install. Preview versions allowed.", call_args[0][0])
self.assertEqual(extension_name, call_args[0][1])
self.assertEqual(mock_logger.warning.call_count, 1)
ext = show_extension(extension_name)
self.assertEqual(ext["name"], extension_name)
self.assertEqual(ext["version"], "1.4.1a1")
remove_extension(extension_name)

def test_add_extension_with_later_preview(self):
extension_name = "extension-test-pkg"
extension1 = 'extension_test_pkg-1.0.0b1-py3-none-any.whl'
extension2 = 'extension_test_pkg-1.2.3-py3-none-any.whl'
extension3 = 'extension_test_pkg-1.4.1a1-py3-none-any.whl'

mocked_index_data = {
extension_name: [
mock_ext(extension1, version='1.0.0b1', download_url=_get_test_data_file(extension1)),
mock_ext(extension2, version='1.2.3', download_url=_get_test_data_file(extension2)),
mock_ext(extension3, version='1.4.1a1', download_url=_get_test_data_file(extension3))
]
}
from knack.util import CLIError
with mock.patch('azure.cli.core.extension._resolve.get_index_extensions',
return_value=mocked_index_data):
with mock.patch('azure.cli.core.extension._resolve.logger') as mock_logger:
add_extension(cmd=self.cmd, extension_name=extension_name)
call_args = mock_logger.warning.call_args
self.assertEqual("Extension '%s' has a later preview version to install, add `--allow-preview True` to try preview version.", call_args[0][0])
self.assertEqual(extension_name, call_args[0][1])
self.assertEqual(mock_logger.warning.call_count, 1)
ext = show_extension(extension_name)
self.assertEqual(ext["name"], extension_name)
self.assertEqual(ext["version"], "1.2.3")
remove_extension(extension_name)

def test_update_extension_with_preview(self):
extension_name = "extension-test-pkg"
extension1 = 'extension_test_pkg-1.0.0b1-py3-none-any.whl'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,7 @@ def add_ingress_appgw_addon_role_assignment(result, cmd):
)
if not add_role_assignment(
cmd,
"Contributor",
"Network Contributor",
service_principal_msi_id,
is_service_principal,
scope=appgw_group_id,
Expand Down Expand Up @@ -943,7 +943,7 @@ def add_ingress_appgw_addon_role_assignment(result, cmd):
)
if not add_role_assignment(
cmd,
"Contributor",
"Network Contributor",
service_principal_msi_id,
is_service_principal,
scope=vnet_id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,8 @@ class ProvisioningStatus:
RUNNING = "Running"
SUCCEEDED = "Succeeded"
FAILED = "Failed"


class ARMAuthenticationMode:
LOCAL = "local"
PASS_THROUGH = "pass-through"
8 changes: 8 additions & 0 deletions src/azure-cli/azure/cli/command_modules/appconfig/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
text: az appconfig create -g MyResourceGroup -n MyAppConfiguration -l westus --sku Standard --assign-identity /subscriptions/<SUBSCRIPTON ID>/resourcegroups/<RESOURCEGROUP>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myUserAssignedIdentity
- name: Create an App Configuration store with name, location and resource group with public network access enabled and local auth disabled.
text: az appconfig create -g MyResourceGroup -n MyAppConfiguration -l westus --enable-public-network --disable-local-auth
- name: Create an App Configuration store with name, location and resource group with ARM authentication mode set to Pass-through.
text: az appconfig create -g MyResourceGroup -n MyAppConfiguration -l westus --arm-auth-mode pass-through
- name: Create an App Configuration store with name, location and resource group with ARM authentication mode set to Pass-through and private network access via ARM Private Link enabled.
text: az appconfig create -g MyResourceGroup -n MyAppConfiguration -l westus --arm-auth-mode pass-through --enable-arm-private-network-access true
"""

helps['appconfig list-deleted'] = """
Expand Down Expand Up @@ -369,6 +373,10 @@
text: az appconfig update -g MyResourceGroup -n MyAppConfiguration --encryption-key-name ""
- name: Update an App Configuration store to enable public network access and disable local auth.
text: az appconfig update -g MyResourceGroup -n MyAppConfiguration --enable-public-network true --disable-local-auth true
- name: Update an App Configuration store to set ARM authentication mode set to Pass-through.
text: az appconfig update -g MyResourceGroup -n MyAppConfiguration --arm-auth-mode pass-through
- name: Update an App Configuration store to set ARM authentication mode set to Pass-through and enable private network access via ARM Private Link.
text: az appconfig update -g MyResourceGroup -n MyAppConfiguration --arm-auth-mode pass-through --enable-arm-private-network-access true
"""

helps['appconfig feature'] = """
Expand Down
19 changes: 18 additions & 1 deletion src/azure-cli/azure/cli/command_modules/appconfig/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
resource_group_name_type)
from azure.cli.core.commands.validators import \
get_default_location_from_resource_group
from ._constants import ImportExportProfiles, ImportMode, FeatureFlagConstants
from ._constants import ImportExportProfiles, ImportMode, FeatureFlagConstants, ARMAuthenticationMode

from ._validators import (validate_appservice_name_or_id, validate_sku, validate_snapshot_query_fields,
validate_connection_string, validate_datetime,
Expand Down Expand Up @@ -119,6 +119,19 @@ def load_arguments(self, _):
help='Filter snapshots by their status. If no status specified, return all snapshots by default.'
)

arm_auth_mode_arg_type = CLIArgumentType(
options_list=['--arm-auth-mode'],
arg_type=get_enum_type([ARMAuthenticationMode.LOCAL, ARMAuthenticationMode.PASS_THROUGH]),
help="The authentication mode for accessing the App Configuration Store via ARM. 'pass-through' (Recommended) uses Microsoft Entra ID to access the store via ARM with proper authorization.'local' uses access keys for authentication. This requires access keys to be enabled."
)

enable_arm_private_network_access_arg_type = CLIArgumentType(
option_list=['--enable-arm-private-network-access'],
arg_type=get_three_state_flag(),
help="Enable access to the App Configuration store via ARM Private Link if resource is restricted to private network access. Requires Pass-through ARM authentication mode."

)

# Used with data plane commands. These take either a store name or connection string argument.
# We only read default values when neither connection string nor store name is provided so configured defaults are not supplied.
data_plane_name_arg_type = CLIArgumentType(
Expand Down Expand Up @@ -160,6 +173,8 @@ def load_arguments(self, _):
c.argument('replica_name', arg_type=store_creation_replica_name_arg_type)
c.argument('replica_location', arg_type=replica_location_arg_type)
c.argument('no_replica', help='Proceed without replica creation for premium tier store.', arg_type=get_three_state_flag())
c.argument('arm_auth_mode', arg_type=arm_auth_mode_arg_type)
c.argument('enable_arm_private_network_access', arg_type=enable_arm_private_network_access_arg_type)

with self.argument_context('appconfig update') as c:
c.argument('sku', help='The sku of the App Configuration store', arg_type=get_enum_type(['Free', 'Premium', 'Standard']))
Expand All @@ -168,6 +183,8 @@ def load_arguments(self, _):
help='When true, requests coming from public networks have permission to access this store while private endpoint is enabled. When false, only requests made through Private Links can reach this store.')
c.argument('disable_local_auth', arg_type=get_three_state_flag(), help='Disable all authentication methods other than AAD authentication.')
c.argument('enable_purge_protection', options_list=['--enable-purge-protection', '-p'], arg_type=get_three_state_flag(), help='Property specifying whether protection against purge is enabled for this App Configuration store. Setting this property to true activates protection against purge for this App Configuration store and its contents. Enabling this functionality is irreversible.')
c.argument('arm_auth_mode', arg_type=arm_auth_mode_arg_type)
c.argument('enable_arm_private_network_access', arg_type=enable_arm_private_network_access_arg_type)

with self.argument_context('appconfig recover') as c:
c.argument('location', arg_type=get_location_type(self.cli_ctx), help='Location of the deleted App Configuration store. Can be viewed using command `az appconfig show-deleted`.')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,13 +377,14 @@ def validate_snapshot_import(namespace):

def validate_sku(namespace):
if namespace.sku.lower() == 'free':
if (namespace.enable_purge_protection or namespace.retention_days or namespace.replica_name or namespace.replica_location or namespace.no_replica):
if (namespace.enable_purge_protection or namespace.retention_days or namespace.replica_name or namespace.replica_location or namespace.no_replica or namespace.enable_arm_private_network_access): # pylint: disable=too-many-boolean-expressions
logger.warning("Options '--enable-purge-protection', '--replica-name', '--replica-location' , '--no-replica' and '--retention-days' will be ignored when creating a free store.")
namespace.retention_days = None
namespace.enable_purge_protection = None
namespace.replica_name = None
namespace.replica_location = None
namespace.no_replica = None
namespace.enable_arm_private_network_access = None
return

if namespace.sku.lower() == 'premium' and not namespace.no_replica:
Expand Down
Loading

0 comments on commit 74382dd

Please sign in to comment.