Skip to content

SQL az sql db: add LTR Immutability Operations#31905

Closed
lixiachena wants to merge 68 commits intoAzure:devfrom
lixiachena:lich/immutable
Closed

SQL az sql db: add LTR Immutability Operations#31905
lixiachena wants to merge 68 commits intoAzure:devfrom
lixiachena:lich/immutable

Conversation

@lixiachena
Copy link
Contributor

@lixiachena lixiachena commented Aug 2, 2025

Related command

This changeset includes

  1. Update azure-mgmt-sql to 4.0.0b22

  2. Add new commands:

    1. az sql db ltr-backup lock-time-based-immutability -l {loc} -s {server_name} -d {database_name} -n {backup_name}
    2. az sql db ltr-backup disable-time-based-immutability -l {loc} -s {server_name} -d {database_name} -n {backup_name}
    3. sql db ltr-backup remove_legal_hold_immutability -l {loc} -s {server_name} -d {database_name} -n {backup_name}
    4. sql db ltr-backup set_legal_hold_immutability -l {loc} -s {server_name} -d {database_name} -n {backup_name}
  3. Modified command .az sql db ltr-policy set

    1. Add a new parameter -immutability-mode {time_based_immutability_mode}
    2. Modify parameter name make_backups_immutable to time-based-immutability

Description

This is to support sql Immutability LTR public review feature
Testing Guide

  1. Set LTR policy with new parmater
    az sql db ltr-policy set --name cli_test_donnotdelete2 --resource-group cli_test_donnotdelete --server clitestserverdonotdeletecanaryeast --time-based-immutability Enabled --subscription 4aebc079-5ec8-4be9-9f4d-39c38f3707cc ---time-based-immutability Locked -weekly-retention P1w

  2. Set legal hold
    az sql db ltr-backup set_legal_hold_immutability -d db1 -s lichcanaryus2 -l eastus2euap --n "f05281db-0c65-42ad-8f54-d259dd7be6e8;133983855330000000;Hot"

  3. Remove legalhold
    az sql db ltr-backup remove_legal_hold_immutability -d db1 -s lichcanaryus2 -l eastus2euap --n "f05281db-0c65-42ad-8f54-d259dd7be6e8;133983855330000000;Hot"

  4. Disable time based immutability
    az sql db ltr-backup disable-time-based-immutability -d db1 -s lichcanaryus2 -l eastus2euap --n "f05281db-0c65-42ad-8f54-d259dd7be6e8;133983855330000000;Hot"

  5. Lock time based immutability
    az sql db ltr-backup lock-time-based-immutability -d db1 -s lichcanaryus2 -l eastus2euap --n "f05281db-0c65-42ad-8f54-d259dd7be6e8;133983855330000000;Hot"


This checklist is used to make sure that common guidelines for a pull request are followed.

@azure-client-tools-bot-prd
Copy link

azure-client-tools-bot-prd bot commented Aug 2, 2025

❌AzureCLI-FullTest
️✔️acr
️✔️latest
️✔️3.12
️✔️3.13
️✔️acs
️✔️latest
️✔️3.12
️✔️3.13
️✔️advisor
️✔️latest
️✔️3.12
️✔️3.13
️✔️ams
️✔️latest
️✔️3.12
️✔️3.13
️✔️apim
️✔️latest
️✔️3.12
️✔️3.13
❌appconfig
❌latest
️✔️3.12
❌3.13
Type Test Case Error Message Line
Failed test_azconfig_mgmt self = <azure.cli.testsdk.base.ExecutionResult object at 0x7fde9b2d4100>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7fde9de86990>
command = 'appconfig create -n MgmtTestPremiumSku000005 -g clitest.rg000001 -l eastus --sku premium --tags key=value --assign-id...tem] --retention-days 1 --enable-purge-protection False --replica-name MgmtTestReplica000006 --replica-location westus'
expect_failure = False

    def in_process_execute(self, cli_ctx, command, expect_failure=False):
        from io import StringIO
        from vcr.errors import CannotOverwriteExistingCassetteException
    
        if command.startswith('az '):
            command = command[3:]
    
        stdout_buf = StringIO()
        logging_buf = StringIO()
        try:
            # issue: stderr cannot be redirect in this form, as a result some failure information
            # is lost when command fails.
>           self.exit_code = cli_ctx.invoke(shlex.split(command), out_file=stdout_buf) or 0
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/azure-cli-testsdk/azure/cli/testsdk/base.py:303: 
                                        
env/lib/python3.13/site-packages/knack/cli.py:245: in invoke
    exit_code = self.exception_handler(ex)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/init.py:130: in exception_handler
    return handle_exception(ex)
           ^^^^^^^^^^^^^^^^^^^^
                                        

ex = ResourceNotFoundError("(SubscriptionNotFound) The subscription '00000000-0000-0000-0000-000000000000' could not be found.\nCode: SubscriptionNotFound\nMessage: The subscription '00000000-0000-0000-0000-000000000000' could not be found.")
args = (), kwargs = {}

    def handle_main_exception(ex, *args, **kwargs):  # pylint: disable=unused-argument
        if isinstance(ex, CannotOverwriteExistingCassetteException):
            # This exception usually caused by a no match HTTP request. This is a product error
            # that is caused by change of SDK invocation.
            raise ex
    
>       raise CliExecutionError(ex)
E       azure.cli.testsdk.exceptions.CliExecutionError: The CLI throws exception ResourceNotFoundError during execution and fails the command.

src/azure-cli-testsdk/azure/cli/testsdk/patches.py:35: CliExecutionError

During handling of the above exception, another exception occurred:

self = <azure.cli.command_modules.appconfig.tests.latest.test_appconfig_mgmt_commands.AppConfigMgmtScenarioTest testMethod=test_azconfig_mgmt>
resource_group = 'clitest.rg000001', location = 'eastus'

    @ResourceGroupPreparer(parameter_name_for_location='location')
    @AllowLargeResponse()
    def test_azconfig_mgmt(self, resource_group, location):
        mgmt_prefix = get_resource_name_prefix('MgmtTest')
    
        # Create store with developer sku
        developer_config_store_name = self.create_random_name(prefix=mgmt_prefix, length=24)
        developer_sku = 'developer'
        location = 'eastus'
    
        self.kwargs.update({
            'config_store_name': developer_config_store_name,
            'rg_loc': location,
            'rg': resource_group,
            'sku': developer_sku
        })
    
        store = self.cmd('appconfig create -n {config_store_name} -g {rg} -l {rg_loc} --sku {sku}',
                         checks=[self.check('name', '{config_store_name}'),
                                 self.check('location', '{rg_loc}'),
                                 self.check('resourceGroup', resource_group),
                                 self.check('provisioningState', 'Succeeded'),
                                 self.check('sku.name', developer_sku)]).get_output_in_json()
    
    
        self.cmd('appconfig show -n {config_store_name} -g {rg}',
                 checks=[self.check('name', '{config_store_name}'),
                         self.check('location', '{rg_loc}'),
                         self.check('resourceGroup', resource_group),
                         self.check('provisioningState', 'Succeeded'),
                         self.check('sku.name', developer_sku)])
    
        self.cmd('appconfig delete -n {config_store_name} -g {rg} -y')
    
        config_store_name = self.create_random_name(prefix=mgmt_prefix, length=24)
        standard_sku = 'standard'
        premium_sku = 'premium'
        tag_key = "key"
        tag_value = "value"
        tag = tag_key + '=' + tag_value
        structured_tag = {tag_key: tag_value}
        system_assigned_identity = '[system]'
    
        self.kwargs.update({
            'config_store_name': config_store_name,
            'rg_loc': location,
            'rg': resource_group,
            'sku': standard_sku,
            'tags': tag,
            'identity': system_assigned_identity,
            'retention_days': 1,
            'enable_purge_protection': False
        })
    
        store = self.cmd('appconfig create -n {config_store_name} -g {rg} -l {rg_loc} --sku {sku} --tags {tags} --assign-identity {identity} --retention-days {retention_days} --enable-purge-protection {enable_purge_protection}',
                         checks=[self.check('name', '{config_store_name}'),
                                 self.check('location', '{rg_loc}'),
                                 self.check('resourceGroup', resource_group),
                                 self.check('provisioningState', 'Succeeded'),
                                 self.check('sku.name', standard_sku),
                                 self.check('tags', structured_tag),
                                 self.check('identity.type', 'SystemAssigned'),
                                 self.check('softDeleteRetentionInDays', '{retention_days}'),
                                 self.check('enablePurgeProtection', '{enable_purge_protection}')]).get_output_in_json()
    
        self.cmd('appconfig list -g {rg}',
                 checks=[self.check('[0].name', '{config_store_name}'),
                         self.check('[0].location', '{rg_loc}'),
                         self.check('[0].resourceGroup', resource_group),
                         self.check('[0].provisioningState', 'Succeeded'),
                         self.check('[0].sku.name', standard_sku),
                         self.check('[0].tags', structured_tag),
                         self.check('[0].identity.type', 'SystemAssigned')])
    
        self.cmd('appconfig show -n {config_store_name} -g {rg}',
                 checks=[self.check('name', '{config_store_name}'),
                         self.check('location', '{rg_loc}'),
                         self.check('resourceGroup', resource_group),
                         self.check('provisioningState', 'Succeeded'),
                         self.check('sku.name', standard_sku),
                         self.check('tags', structured_tag),
                         self.check('identity.type', 'SystemAssigned')])
    
        tag_key = "Env"
        tag_value = "Prod"
        updated_tag = tag_key + '=' + tag_value
        structured_tag = {tag_key: tag_value}
        self.kwargs.update({
            'updated_tag': updated_tag,
            'update_sku': premium_sku   # update to premium sku
        })
    
        self.cmd('appconfig update -n {config_store_name} -g {rg} --tags {updated_tag} --sku {update_sku}',
                 checks=[self.check('name', '{config_store_name}'),
                         self.check('location', '{rg_loc}'),
                         self.check('resourceGroup', resource_group),
                         self.check('tags', structured_tag),
                         self.check('provisioningState', 'Succeeded'),
                         self.check('sku.name', premium_sku)])
    
        keyvault_prefix = get_resource_name_prefix('cmk-test-keyvault')
        keyvault_name = self.create_random_name(prefix=keyvault_prefix, length=24)
        encryption_key = 'key'
        system_assigned_identity_id = store['identity']['principalId']
        self.kwargs.update({
            'encryption_key': encryption_key,
            'keyvault_name': keyvault_name,
            'identity_id': system_assigned_identity_id
        })
    
        keyvault = setup_key_vault(self, self.kwargs)
        keyvault_uri = keyvault['properties']['vaultUri']
        self.kwargs.update({
            'keyvault_uri': keyvault_uri,
        })
    
        self.cmd('appconfig update -n {config_store_name} -g {rg} --encryption-key-name {encryption_key} --encryption-key-vault {keyvault_uri}',
                 checks=[self.check('name', '{config_store_name}'),
                         self.check('location', '{rg_loc}'),
                         self.check('resourceGroup', resource_group),
                         self.check('tags', structured_tag),
                         self.check('provisioningState', 'Succeeded'),
                         self.check('sku.name', premium_sku),
                         self.check('encryption.keyVaultProperties.keyIdentifier', keyvault_uri.strip('/') + "/keys/{}/".format(encryption_key))])
    
        self.kwargs.update({
            'updated_tag': '""',
        })
    
        self.cmd('appconfig update -n {config_store_name} -g {rg} --tags {updated_tag}',
            checks=[self.check('name', '{config_store_name}'),
                    self.check('location', '{rg_loc}'),
                    self.check('resourceGroup', resource_group),
                    self.check('tags', {}),
                    self.check('provisioningState', 'Succeeded'),
                    self.check('sku.name', premium_sku),
                    self.check('encryption.keyVaultProperties.keyIdentifier', keyvault_uri.strip('/') + "/keys/{}/".format(encryption_key))])
    
        # update private link delegation mode and private network access
        pass_through_auth_mode = 'pass-through'
        local_auth_mode = "local"
    
        # update authentication mode to 'local'
        self.kwargs.update({
            'data_plane_auth_mode': local_auth_mode,
        })
    
        self.cmd('appconfig update -n {config_store_name} -g {rg} --arm-auth-mode {data_plane_auth_mode}',
                 checks=[self.check('name', '{config_store_name}'),
                    self.check('location', '{rg_loc}'),
                    self.check('resourceGroup', resource_group),
                    self.check('tags', {}),
                    self.check('provisioningState', 'Succeeded'),
                    self.check('dataPlaneProxy.authenticationMode', 'Local')])
    
        # enabling private network access should fail
        with self.assertRaisesRegex(HttpResponseError, 'Data plane proxy authentication mode must be set to Pass-through to enable private link delegation'):
            self.cmd('appconfig update -n {config_store_name} -g {rg} --enable-arm-private-network-access')
    
        # update authengication mode to 'pass-through'
        self.kwargs.update({
            'data_plane_auth_mode': pass_through_auth_mode,
        })
    
        self.cmd('appconfig update -n {config_store_name} -g {rg} --arm-auth-mode {data_plane_auth_mode}',
                 checks=[self.check('name', '{config_store_name}'),
                    self.check('location', '{rg_loc}'),
                    self.check('resourceGroup', resource_group),
                    self.check('tags', {}),
                    self.check('provisioningState', 'Succeeded'),
                    self.check('dataPlaneProxy.authenticationMode', 'Pass-through')])
    
        self.cmd('appconfig update -n {config_store_name} -g {rg} --enable-arm-private-network-access',
                 checks=[self.check('name', '{config_store_name}'),
                    self.check('location', '{rg_loc}'),
                    self.check('resourceGroup', resource_group),
                    self.check('tags', {}),
                    self.check('provisioningState', 'Succeeded'),
                    self.check('dataPlaneProxy.privateLinkDelegation', 'Enabled')])
    
        self.cmd('appconfig delete -n {config_store_name} -g {rg} -y')
    
        # create store in premium tier with replica
        premium_store_prefix = get_resource_name_prefix('MgmtTestPremiumSku')
        replica_prefix = get_resource_name_prefix('MgmtTestReplica')
        config_store_name = self.create_random_name(prefix=premium_store_prefix, length=24)
        replica_name = self.create_random_name(prefix=replica_prefix, length=24)
        tag_key = "key"
        tag_value = "value"
        tag = tag_key + '=' + tag_value
        structured_tag = {tag_key: tag_value}
    
        self.kwargs.update({
            "premium_sku": premium_sku,
            "config_store_name": config_store_name,
            "replica_name": replica_name,
            "replica_location": "westus",
            "tags": tag
        })
    
>       store = self.cmd('appconfig create -n {config_store_name} -g {rg} -l {rg_loc} --sku {premium_sku} --tags {tags} --assign-identity {identity} --retention-days {retention_days} --enable-purge-protection {enable_purge_protection} --replica-name {replica_name} --replica-location {replica_location}',
                         checks=[self.check('name', '{config_store_name}'),
                                 self.check('location', '{rg_loc}'),
                                 self.check('resourceGroup', resource_group),
                                 self.check('provisioningState', 'Succeeded'),
                                 self.check('sku.name', premium_sku),
                                 self.check('tags', structured_tag),
                                 self.check('identity.type', 'SystemAssigned'),
                                 self.check('softDeleteRetentionInDays', '{retention_days}'),
                                 self.check('enablePurgeProtection', '{enable_purge_protection}')]).get_output_in_json()

src/azure-cli/azure/cli/command_modules/appconfig/tests/latest/test_appconfig_mgmt_commands.py:227: 
 
 
                                      
src/azure-cli-testsdk/azure/cli/testsdk/base.py:177: in cmd
    return execute(self.cli_ctx, command, expect_failure=expect_failure).assert_with_checks(checks)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-testsdk/azure/cli/testsdk/base.py:252: in init
    self.in_process_execute(cli_ctx, command, expect_failure=expect_failure)
src/azure-cli-testsdk/azure/cli/testsdk/base.py:315: in in_process_execute
    raise ex.exception
env/lib/python3.13/site-packages/knack/cli.py:233: in invoke
    cmd_result = self.invocation.execute(args)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:666: in execute
    raise ex
src/azure-cli-core/azure/cli/core/commands/init.py:734: in run_jobs_serially
    results.append(self.run_job(expanded_arg, cmd_copy))
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:703: in run_job
    result = cmd_copy(params)
             ^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:336: in call
    return self.handler(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/command_operation.py:120: in handler
    return op(**command_args)
           ^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/appconfig/custom.py:102: in create_configstore
    store_replica = create_replica(cmd, replica_client, name, replica_name, replica_location, resource_group_name)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/appconfig/custom.py:337: in create_replica
    return client.begin_create(resource_group_name=resource_group_name,
env/lib/python3.13/site-packages/azure/core/tracing/decorator.py:119: in wrapper_use_tracer
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/azure/mgmt/appconfiguration/operations/replicas_operations.py:526: in begin_create
    raw_result = self.create_initial(
env/lib/python3.13/site-packages/azure/mgmt/appconfiguration/operations/replicas_operations.py:420: in create_initial
    map_error(status_code=response.status_code, response=response, error_map=error_map)
 
 
 
 
 
 
 
 
 
                               

status_code = 404
response = HttpResponse: 404 Not Found, Content-Type: application/json; charset=utf-8
error_map = {304: <class 'azure.core.exceptions.ResourceNotModifiedError'>, 401: <class 'azure.core.exceptions.ClientAuthenticatio..., 404: <class 'azure.core.exceptions.ResourceNotFoundError'>, 409: <class 'azure.core.exceptions.ResourceExistsError'>}

    def map_error(
        status_code: int,
        response: _HttpResponseCommonAPI,
        error_map: Mapping[int, Type[HttpResponseError]],
    ) -> None:
        if not error_map:
            return
        error_type = error_map.get(status_code)
        if not error_type:
            return
        error = error_type(response=response)
>       raise error
E       azure.core.exceptions.ResourceNotFoundError: (SubscriptionNotFound) The subscription '00000000-0000-0000-0000-000000000000' could not be found.
E       Code: SubscriptionNotFound
E       Message: The subscription '00000000-0000-0000-0000-000000000000' could not be found.

env/lib/python3.13/site-packages/azure/core/exceptions.py:163: ResourceNotFoundError
azure/cli/command_modules/appconfig/tests/latest/test_appconfig_mgmt_commands.py:26
️✔️appservice
️✔️latest
️✔️3.12
️✔️3.13
️✔️aro
️✔️latest
️✔️3.12
️✔️3.13
️✔️backup
️✔️latest
️✔️3.12
️✔️3.13
️✔️batch
️✔️latest
️✔️3.12
️✔️3.13
️✔️batchai
️✔️latest
️✔️3.12
️✔️3.13
️✔️billing
️✔️latest
️✔️3.12
️✔️3.13
️✔️botservice
️✔️latest
️✔️3.12
️✔️3.13
️✔️cdn
️✔️latest
️✔️3.12
️✔️3.13
️✔️cloud
️✔️latest
️✔️3.12
️✔️3.13
️✔️cognitiveservices
️✔️latest
️✔️3.12
️✔️3.13
️✔️compute_recommender
️✔️latest
️✔️3.12
️✔️3.13
️✔️computefleet
️✔️latest
️✔️3.12
️✔️3.13
️✔️config
️✔️latest
️✔️3.12
️✔️3.13
️✔️configure
️✔️latest
️✔️3.12
️✔️3.13
️✔️consumption
️✔️latest
️✔️3.12
️✔️3.13
️✔️container
️✔️latest
️✔️3.12
️✔️3.13
️✔️containerapp
️✔️latest
️✔️3.12
️✔️3.13
️✔️core
️✔️latest
️✔️3.12
️✔️3.13
️✔️cosmosdb
️✔️latest
️✔️3.12
️✔️3.13
️✔️databoxedge
️✔️latest
️✔️3.12
️✔️3.13
️✔️dls
️✔️latest
️✔️3.12
️✔️3.13
️✔️dms
️✔️latest
️✔️3.12
️✔️3.13
️✔️eventgrid
️✔️latest
️✔️3.12
️✔️3.13
️✔️eventhubs
️✔️latest
️✔️3.12
️✔️3.13
️✔️feedback
️✔️latest
️✔️3.12
️✔️3.13
️✔️find
️✔️latest
️✔️3.12
️✔️3.13
️✔️hdinsight
️✔️latest
️✔️3.12
️✔️3.13
️✔️identity
️✔️latest
️✔️3.12
️✔️3.13
️✔️iot
️✔️latest
️✔️3.12
️✔️3.13
️✔️keyvault
️✔️latest
️✔️3.12
️✔️3.13
️✔️lab
️✔️latest
️✔️3.12
️✔️3.13
️✔️managedservices
️✔️latest
️✔️3.12
️✔️3.13
️✔️maps
️✔️latest
️✔️3.12
️✔️3.13
️✔️marketplaceordering
️✔️latest
️✔️3.12
️✔️3.13
️✔️monitor
️✔️latest
️✔️3.12
️✔️3.13
️✔️mysql
️✔️latest
️✔️3.12
️✔️3.13
️✔️netappfiles
️✔️latest
️✔️3.12
️✔️3.13
️✔️network
️✔️latest
️✔️3.12
️✔️3.13
️✔️policyinsights
️✔️latest
️✔️3.12
️✔️3.13
️✔️privatedns
️✔️latest
️✔️3.12
️✔️3.13
️✔️profile
️✔️latest
️✔️3.12
️✔️3.13
️✔️rdbms
️✔️latest
️✔️3.12
️✔️3.13
️✔️redis
️✔️latest
️✔️3.12
️✔️3.13
️✔️relay
️✔️latest
️✔️3.12
️✔️3.13
️✔️resource
️✔️latest
️✔️3.12
️✔️3.13
️✔️role
️✔️latest
️✔️3.12
️✔️3.13
️✔️search
️✔️latest
️✔️3.12
️✔️3.13
️✔️security
️✔️latest
️✔️3.12
️✔️3.13
️✔️servicebus
️✔️latest
️✔️3.12
️✔️3.13
️✔️serviceconnector
️✔️latest
️✔️3.12
️✔️3.13
️✔️servicefabric
️✔️latest
️✔️3.12
️✔️3.13
️✔️signalr
️✔️latest
️✔️3.12
️✔️3.13
❌sql
❌latest
❌3.12
Type Test Case Error Message Line
Failed test_sql_server_create_with_tags self = <azure.cli.testsdk.base.ExecutionResult object at 0x7f853e850d70>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7f85453f0c20>
command = 'sql server create -g clitest.rg000001 --name clitestserver000002 --admin-user admin123 --admin-password SecretPassword123 --tags env=test purpose=demo'
expect_failure = False

    def in_process_execute(self, cli_ctx, command, expect_failure=False):
        from io import StringIO
        from vcr.errors import CannotOverwriteExistingCassetteException
    
        if command.startswith('az '):
            command = command[3:]
    
        stdout_buf = StringIO()
        logging_buf = StringIO()
        try:
            # issue: stderr cannot be redirect in this form, as a result some failure information
            # is lost when command fails.
>           self.exit_code = cli_ctx.invoke(shlex.split(command), out_file=stdout_buf) or 0
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/azure-cli-testsdk/azure/cli/testsdk/base.py:303: 
                                        
env/lib/python3.12/site-packages/knack/cli.py:245: in invoke
    exit_code = self.exception_handler(ex)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/init.py:130: in exception_handler
    return handle_exception(ex)
           ^^^^^^^^^^^^^^^^^^^^
src/azure-cli-testsdk/azure/cli/testsdk/patches.py:33: in handle_main_exception
    raise ex
env/lib/python3.12/site-packages/knack/cli.py:233: in invoke
    cmd_result = self.invocation.execute(args)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:666: in execute
    raise ex
src/azure-cli-core/azure/cli/core/commands/init.py:734: in run_jobs_serially
    results.append(self.run_job(expanded_arg, cmd_copy))
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:703: in run_job
    result = cmd_copy(params)
             ^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:336: in call
    return self.handler(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/command_operation.py:120: in handler
    return op(**command_args)
           ^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/sql/custom.py:4220: in server_create
    return sdk_no_wait(no_wait, client.begin_create_or_update,
src/azure-cli-core/azure/cli/core/util.py:759: in sdk_no_wait
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/tracing/decorator.py:119: in wrapper_use_tracer
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/mgmt/sql/operations/servers_operations.py:816: in begin_create_or_update
    raw_result = self.create_or_update_initial(
env/lib/python3.12/site-packages/azure/mgmt/sql/operations/servers_operations.py:708: in create_or_update_initial
    pipeline_response: PipelineResponse = self.client.pipeline.run(  # pylint: disable=protected-access
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:242: in run
    return first_node.send(pipeline_request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/mgmt/core/policies/base.py:95: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/policies/redirect.py:205: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/policies/retry.py:545: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/policies/authentication.py:159: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:130: in send
    self.sender.send(request.http_request, **request.context.options),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/transport/requests_basic.py:365: in send
    response = self.session.request(  # type: ignore
env/lib/python3.12/site-packages/requests/sessions.py:589: in request
    resp = self.send(prep, **send_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/requests/sessions.py:703: in send
    r = adapter.send(request, **kwargs)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/requests/adapters.py:667: in send
    resp = conn.urlopen(
env/lib/python3.12/site-packages/urllib3/connectionpool.py:787: in urlopen
    response = self.make_request(
env/lib/python3.12/site-packages/urllib3/connectionpool.py:534: in make_request
    response = conn.getresponse()
               ^^^^^^^^^^^^^^^^^^
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
          

self = <vcr.patch.VCRRequestsHTTPSConnection/mnt/vss/work/1/s/src/azure-cli/azure/cli/command_modules/sql/tests/latest/recordings/test_sql_server_create_with_tags.yaml object at 0x7f853e3b7fe0>
 = False, kwargs = {}

    def getresponse(self, 
=False, **kwargs):
        """Retrieve the response"""
        # Check to see if the cassette has a response for this request. If so,
        # then return it
        if self.cassette.can_play_response_for(self.vcr_request):
            log.info(f"Playing response for {self.vcr_request} from cassette")
            response = self.cassette.play_response(self.vcr_request)
            return VCRHTTPResponse(response)
        else:
            if self.cassette.write_protected and self.cassette.filter_request(self.vcr_request):
>               raise CannotOverwriteExistingCassetteException(
                    cassette=self.cassette,
                    failed_request=self.vcr_request,
                )
E               vcr.errors.CannotOverwriteExistingCassetteException: Can't overwrite existing cassette ('/mnt/vss/work/1/s/src/azure-cli/azure/cli/command_modules/sql/tests/latest/recordings/test_sql_server_create_with_tags.yaml') in your current record mode ('once').
E               No match for the request (<Request (PUT) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000002?api-version=2024-11-01-preview>)&nbsp;was&nbsp;found.
E               Found 1 similar requests with 1 different matcher(s) :
E               
E               1 - (<Request (PUT) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000002?api-version=2024-05-01-preview>).
E               Matchers succeeded : ['method', 'scheme', 'host', 'port', 'path']
E               Matchers failed :
E               custom_request_query_matcher - assertion failure :
E               None

env/lib/python3.12/site-packages/vcr/stubs/init.py:264: CannotOverwriteExistingCassetteException

During handling of the above exception, another exception occurred:

self = <azure.cli.command_modules.sql.tests.latest.test_sql_commands.SqlServerMgmtScenarioTest testMethod=test_sql_server_create_with_tags>
resource_group = 'clitest.rg000001', resource_group_location = 'westeurope'

    @ResourceGroupPreparer(parameter_name='resource_group', location='westeurope')
    def test_sql_server_create_with_tags(self, resource_group, resource_group_location):
        server_name = self.create_random_name(server_name_prefix, server_name_max_length)
        admin_login = 'admin123'
        admin_password = 'SecretPassword123'
    
        # test create sql server with tags
>       server = self.cmd('sql server create -g {} --name {} '
                         '--admin-user {} --admin-password {} '
                         '--tags env=test purpose=demo'
                         .format(resource_group, server_name, admin_login, admin_password),
                         checks=[
                             JMESPathCheck('name', server_name),
                             JMESPathCheck('location', resource_group_location),
                             JMESPathCheck('resourceGroup', resource_group),
                             JMESPathCheck('administratorLogin', admin_login),
                             JMESPathCheck('tags.env', 'test'),
                             JMESPathCheck('tags.purpose', 'demo')]).get_output_in_json()

src/azure-cli/azure/cli/command_modules/sql/tests/latest/test_sql_commands.py:295: 
 
 
 
 
 
 
                                  
src/azure-cli-testsdk/azure/cli/testsdk/base.py:177: in cmd
    return execute(self.cli_ctx, command, expect_failure=expect_failure).assert_with_checks(checks)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-testsdk/azure/cli/testsdk/base.py:252: in init
    self.in_process_execute(cli_ctx, command, expect_failure=expect_failure)
 
                                       

self = <azure.cli.testsdk.base.ExecutionResult object at 0x7f853e850d70>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7f85453f0c20>
command = 'sql server create -g clitest.rg000001 --name clitestserver000002 --admin-user admin123 --admin-password SecretPassword123 --tags env=test purpose=demo'
expect_failure = False

    def _in_process_execute(self, cli_ctx, command, expect_failure=False):
        from io import StringIO
        from vcr.errors import CannotOverwriteExistingCassetteException
    
        if command.startswith('az '):
            command = command[3:]
    
        stdout_buf = StringIO()
        logging_buf = StringIO()
        try:
            # issue: stderr cannot be redirect in this form, as a result some failure information
            # is lost when command fails.
            self.exit_code = cli_ctx.invoke(shlex.split(command), out_file=stdout_buf) or 0
            self.output = stdout_buf.getvalue()
            self.applog = logging_buf.getvalue()
    
        except CannotOverwriteExistingCassetteException as ex:
>           raise AssertionError(ex)
E           AssertionError: Can't overwrite existing cassette ('/mnt/vss/_work/1/s/src/azure-cli/azure/cli/command_modules/sql/tests/latest/recordings/test_sql_server_create_with_tags.yaml') in your current record mode ('once').
E           No match for the request (<Request (PUT) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000002?api-version=2024-11-01-preview>)&nbsp;was&nbsp;found.
E           Found 1 similar requests with 1 different matcher(s) :
E           
E           1 - (<Request (PUT) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000002?api-version=2024-05-01-preview>).
E           Matchers succeeded : ['method', 'scheme', 'host', 'port', 'path']
E           Matchers failed :
E           _custom_request_query_matcher - assertion failure :
E           None

src/azure-cli-testsdk/azure/cli/testsdk/base.py:308: AssertionError
azure/cli/command_modules/sql/tests/latest/test_sql_commands.py:287
❌3.13
Type Test Case Error Message Line
Failed test_sql_server_create_with_tags self = <azure.cli.testsdk.base.ExecutionResult object at 0x7f2c90791be0>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7f2c931edbd0>
command = 'sql server create -g clitest.rg000001 --name clitestserver000002 --admin-user admin123 --admin-password SecretPassword123 --tags env=test purpose=demo'
expect_failure = False

    def in_process_execute(self, cli_ctx, command, expect_failure=False):
        from io import StringIO
        from vcr.errors import CannotOverwriteExistingCassetteException
    
        if command.startswith('az '):
            command = command[3:]
    
        stdout_buf = StringIO()
        logging_buf = StringIO()
        try:
            # issue: stderr cannot be redirect in this form, as a result some failure information
            # is lost when command fails.
>           self.exit_code = cli_ctx.invoke(shlex.split(command), out_file=stdout_buf) or 0
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/azure-cli-testsdk/azure/cli/testsdk/base.py:303: 
                                        
env/lib/python3.13/site-packages/knack/cli.py:245: in invoke
    exit_code = self.exception_handler(ex)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/init.py:130: in exception_handler
    return handle_exception(ex)
           ^^^^^^^^^^^^^^^^^^^^
src/azure-cli-testsdk/azure/cli/testsdk/patches.py:33: in handle_main_exception
    raise ex
env/lib/python3.13/site-packages/knack/cli.py:233: in invoke
    cmd_result = self.invocation.execute(args)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:666: in execute
    raise ex
src/azure-cli-core/azure/cli/core/commands/init.py:734: in run_jobs_serially
    results.append(self.run_job(expanded_arg, cmd_copy))
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:703: in run_job
    result = cmd_copy(params)
             ^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:336: in call
    return self.handler(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/command_operation.py:120: in handler
    return op(**command_args)
           ^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/sql/custom.py:4220: in server_create
    return sdk_no_wait(no_wait, client.begin_create_or_update,
src/azure-cli-core/azure/cli/core/util.py:759: in sdk_no_wait
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/azure/core/tracing/decorator.py:119: in wrapper_use_tracer
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/azure/mgmt/sql/operations/servers_operations.py:816: in begin_create_or_update
    raw_result = self.create_or_update_initial(
env/lib/python3.13/site-packages/azure/mgmt/sql/operations/servers_operations.py:708: in create_or_update_initial
    pipeline_response: PipelineResponse = self.client.pipeline.run(  # pylint: disable=protected-access
env/lib/python3.13/site-packages/azure/core/pipeline/base.py:242: in run
    return first_node.send(pipeline_request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/azure/mgmt/core/policies/base.py:95: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/azure/core/pipeline/policies/redirect.py:205: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/azure/core/pipeline/policies/retry.py:545: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/azure/core/pipeline/policies/authentication.py:159: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/azure/core/pipeline/base.py:130: in send
    self.sender.send(request.http_request, **request.context.options),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/azure/core/pipeline/transport/requests_basic.py:365: in send
    response = self.session.request(  # type: ignore
env/lib/python3.13/site-packages/requests/sessions.py:589: in request
    resp = self.send(prep, **send_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/requests/sessions.py:703: in send
    r = adapter.send(request, **kwargs)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.13/site-packages/requests/adapters.py:667: in send
    resp = conn.urlopen(
env/lib/python3.13/site-packages/urllib3/connectionpool.py:787: in urlopen
    response = self.make_request(
env/lib/python3.13/site-packages/urllib3/connectionpool.py:534: in make_request
    response = conn.getresponse()
               ^^^^^^^^^^^^^^^^^^
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
          

self = <vcr.patch.VCRRequestsHTTPSConnection/mnt/vss/work/1/s/src/azure-cli/azure/cli/command_modules/sql/tests/latest/recordings/test_sql_server_create_with_tags.yaml object at 0x7f2c90130f50>
 = False, kwargs = {}

    def getresponse(self, 
=False, **kwargs):
        """Retrieve the response"""
        # Check to see if the cassette has a response for this request. If so,
        # then return it
        if self.cassette.can_play_response_for(self.vcr_request):
            log.info(f"Playing response for {self.vcr_request} from cassette")
            response = self.cassette.play_response(self.vcr_request)
            return VCRHTTPResponse(response)
        else:
            if self.cassette.write_protected and self.cassette.filter_request(self.vcr_request):
>               raise CannotOverwriteExistingCassetteException(
                    cassette=self.cassette,
                    failed_request=self.vcr_request,
                )
E               vcr.errors.CannotOverwriteExistingCassetteException: Can't overwrite existing cassette ('/mnt/vss/work/1/s/src/azure-cli/azure/cli/command_modules/sql/tests/latest/recordings/test_sql_server_create_with_tags.yaml') in your current record mode ('once').
E               No match for the request (<Request (PUT) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000002?api-version=2024-11-01-preview>)&nbsp;was&nbsp;found.
E               Found 1 similar requests with 1 different matcher(s) :
E               
E               1 - (<Request (PUT) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000002?api-version=2024-05-01-preview>).
E               Matchers succeeded : ['method', 'scheme', 'host', 'port', 'path']
E               Matchers failed :
E               custom_request_query_matcher - assertion failure :
E               None

env/lib/python3.13/site-packages/vcr/stubs/init.py:264: CannotOverwriteExistingCassetteException

During handling of the above exception, another exception occurred:

self = <azure.cli.command_modules.sql.tests.latest.test_sql_commands.SqlServerMgmtScenarioTest testMethod=test_sql_server_create_with_tags>
resource_group = 'clitest.rg000001', resource_group_location = 'westeurope'

    @ResourceGroupPreparer(parameter_name='resource_group', location='westeurope')
    def test_sql_server_create_with_tags(self, resource_group, resource_group_location):
        server_name = self.create_random_name(server_name_prefix, server_name_max_length)
        admin_login = 'admin123'
        admin_password = 'SecretPassword123'
    
        # test create sql server with tags
>       server = self.cmd('sql server create -g {} --name {} '
                         '--admin-user {} --admin-password {} '
                         '--tags env=test purpose=demo'
                         .format(resource_group, server_name, admin_login, admin_password),
                         checks=[
                             JMESPathCheck('name', server_name),
                             JMESPathCheck('location', resource_group_location),
                             JMESPathCheck('resourceGroup', resource_group),
                             JMESPathCheck('administratorLogin', admin_login),
                             JMESPathCheck('tags.env', 'test'),
                             JMESPathCheck('tags.purpose', 'demo')]).get_output_in_json()

src/azure-cli/azure/cli/command_modules/sql/tests/latest/test_sql_commands.py:295: 
 
 
 
 
 
 
                                  
src/azure-cli-testsdk/azure/cli/testsdk/base.py:177: in cmd
    return execute(self.cli_ctx, command, expect_failure=expect_failure).assert_with_checks(checks)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-testsdk/azure/cli/testsdk/base.py:252: in init
    self.in_process_execute(cli_ctx, command, expect_failure=expect_failure)
 
                                       

self = <azure.cli.testsdk.base.ExecutionResult object at 0x7f2c90791be0>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7f2c931edbd0>
command = 'sql server create -g clitest.rg000001 --name clitestserver000002 --admin-user admin123 --admin-password SecretPassword123 --tags env=test purpose=demo'
expect_failure = False

    def _in_process_execute(self, cli_ctx, command, expect_failure=False):
        from io import StringIO
        from vcr.errors import CannotOverwriteExistingCassetteException
    
        if command.startswith('az '):
            command = command[3:]
    
        stdout_buf = StringIO()
        logging_buf = StringIO()
        try:
            # issue: stderr cannot be redirect in this form, as a result some failure information
            # is lost when command fails.
            self.exit_code = cli_ctx.invoke(shlex.split(command), out_file=stdout_buf) or 0
            self.output = stdout_buf.getvalue()
            self.applog = logging_buf.getvalue()
    
        except CannotOverwriteExistingCassetteException as ex:
>           raise AssertionError(ex)
E           AssertionError: Can't overwrite existing cassette ('/mnt/vss/_work/1/s/src/azure-cli/azure/cli/command_modules/sql/tests/latest/recordings/test_sql_server_create_with_tags.yaml') in your current record mode ('once').
E           No match for the request (<Request (PUT) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000002?api-version=2024-11-01-preview>)&nbsp;was&nbsp;found.
E           Found 1 similar requests with 1 different matcher(s) :
E           
E           1 - (<Request (PUT) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000002?api-version=2024-05-01-preview>).
E           Matchers succeeded : ['method', 'scheme', 'host', 'port', 'path']
E           Matchers failed :
E           _custom_request_query_matcher - assertion failure :
E           None

src/azure-cli-testsdk/azure/cli/testsdk/base.py:308: AssertionError
azure/cli/command_modules/sql/tests/latest/test_sql_commands.py:287
️✔️sqlvm
️✔️latest
️✔️3.12
️✔️3.13
️✔️storage
️✔️latest
️✔️3.12
️✔️3.13
️✔️synapse
️✔️latest
️✔️3.12
️✔️3.13
️✔️telemetry
️✔️latest
️✔️3.12
️✔️3.13
️✔️util
️✔️latest
️✔️3.12
️✔️3.13
️✔️vm
️✔️latest
️✔️3.12
️✔️3.13

@azure-client-tools-bot-prd
Copy link

azure-client-tools-bot-prd bot commented Aug 2, 2025

️✔️AzureCLI-BreakingChangeTest
️✔️Non Breaking Changes

@yonzhan
Copy link
Collaborator

yonzhan commented Aug 2, 2025

Thank you for your contribution! We will review the pull request and get back to you soon.

@github-actions
Copy link

github-actions bot commented Aug 2, 2025

The git hooks are available for azure-cli and azure-cli-extensions repos. They could help you run required checks before creating the PR.

Please sync the latest code with latest dev branch (for azure-cli) or main branch (for azure-cli-extensions).
After that please run the following commands to enable git hooks:

pip install azdev --upgrade
azdev setup -c <your azure-cli repo path> -r <your azure-cli-extensions repo path>

@lixiachena lixiachena changed the title Draft Add LTR Immutability Operations SQL Update azure-mgmt-sq to 4.0.0b22 and add LTR Immutability Operations Aug 6, 2025
@lixiachena lixiachena changed the title SQL Update azure-mgmt-sq to 4.0.0b22 and add LTR Immutability Operations SQL az sql db: add LTR Immutability Operations Aug 6, 2025
@lixiachena lixiachena marked this pull request as ready for review August 6, 2025 16:00
Copilot AI review requested due to automatic review settings August 6, 2025 16:00
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR updates Azure SQL functionality to support Long-Term Retention (LTR) immutability operations by upgrading the azure-mgmt-sql library and adding new commands for managing backup immutability settings.

Key changes include:

  • Upgrade azure-mgmt-sql dependency to version 4.0.0b22
  • Addition of four new commands for LTR backup immutability operations
  • Update of existing LTR policy command with new parameter naming and functionality

Reviewed Changes

Copilot reviewed 12 out of 83 changed files in this pull request and generated 5 comments.

File Description
src/azure-cli/setup.py Updates azure-mgmt-sql version from 4.0.0b21 to 4.0.0b22
src/azure-cli/requirements.py3.*.txt Updates azure-mgmt-sql dependency version across all platform requirement files
test_sql_commands.py Adds comprehensive test suite for new LTR immutability operations and updates existing tests
test_sql_*.yaml Updates test recordings to reflect API version changes and new functionality

'yearly_retention': 'P2M',
'week_of_year': 12,
'make_backups_immutable': 'False',
'time_based_mmutability': 'False',
Copy link

Copilot AI Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable name 'time_based_mmutability' contains a typo. It should be 'time_based_immutability' to match the intended functionality.

Suggested change
'time_based_mmutability': 'False',
'time_based_immutability': 'False',

Copilot uses AI. Check for mistakes.
' --weekly-retention {weekly_retention} --monthly-retention {monthly_retention}'
' --yearly-retention {yearly_retention} --week-of-year {week_of_year}'
' --make-backups-immutable {make_backups_immutable}',
' --time-based-immutability {time_based_immutability}',
Copy link

Copilot AI Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test is referencing '{time_based_immutability}' which is not defined in the kwargs for this test. Based on the typo in line 1385, this should reference '{time_based_mmutability}' or the typo should be fixed.

Copilot uses AI. Check for mistakes.
self.check('monthlyRetention', '{monthly_retention}'),
self.check('yearlyRetention', '{yearly_retention}'),
self.check('makeBackupsImmutable', '{make_backups_immutable}')])
self.check('timeBasedImmutability', '{time_based_immutability}')])
Copy link

Copilot AI Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assertion is checking for '{time_based_immutability}' which is not defined in the test's kwargs. This will cause the test to fail.

Copilot uses AI. Check for mistakes.
self.check('monthlyRetention', '{monthly_retention}'),
self.check('yearlyRetention', '{yearly_retention}'),
self.check('makeBackupsImmutable', '{make_backups_immutable}')])
self.check('timeBasedImmutability', '{time_based_immutability}')])
Copy link

Copilot AI Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assertion is checking for '{time_based_immutability}' which is not defined in the test's kwargs. This will cause the test to fail.

Copilot uses AI. Check for mistakes.
self.check('name', '{backup_name}')])

self.check('name', '{backup_name}'),
self.check('timeBasedImmutability', '{time_based_immutability}')])
Copy link

Copilot AI Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assertion is referencing '{time_based_immutability}' but the variable is defined as '{time_based_mmutability}' (with typo) in the kwargs. This will cause the test to fail.

Copilot uses AI. Check for mistakes.
@lixiachena
Copy link
Contributor Author

Create a new PR since this PR merged so many times and merged files are incorrect

@lixiachena lixiachena closed this Aug 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.