Skip to content

fix(aks): preserve existing ACNS settings during partial updates#33049

Open
nddq wants to merge 1 commit intoAzure:devfrom
nddq:fix/acns-update-preserve-existing-state-v2
Open

fix(aks): preserve existing ACNS settings during partial updates#33049
nddq wants to merge 1 commit intoAzure:devfrom
nddq:fix/acns-update-preserve-existing-state-v2

Conversation

@nddq
Copy link
Copy Markdown
Member

@nddq nddq commented Mar 25, 2026

Currently update_network_profile_advanced_networking creates a new AdvancedNetworking object on every update call, replacing the existing one wholesale. When a user updates only a single ACNS sub-property (e.g. --acns-advanced-networkpolicies L7), existing sub-properties like observability, security, and transit encryption are discarded because they weren't re-specified.

This PR changes the update path to modify the existing AdvancedNetworking object in-place, only overwriting fields the user explicitly provided.

  • Decorator: Mutate mc.network_profile.advanced_networking in-place instead of constructing a fresh object and replacing it
  • Unit tests: Add test_update_network_profile_advanced_networking_preserves_existing_state covering partial updates to network policies, observability, and disable flows
  • Live test: Add test_aks_update_acns_preserves_existing_settings — creates a cluster with ACNS, updates only network policies, then updates only transit encryption, verifying all existing settings survive each step

Testing

Unit tests:

python -m pytest src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_managed_cluster_decorator.py -k "test_update_network_profile_advanced_networking" -xvs
# 4 passed

Live test:

python -m pytest src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_aks_commands.py -k "test_aks_update_acns_preserves_existing_settings" -xvs
# 1 passed in 864.37s

Copilot AI review requested due to automatic review settings March 25, 2026 21:27
@azure-client-tools-bot-prd
Copy link
Copy Markdown

azure-client-tools-bot-prd bot commented Mar 25, 2026

❌AzureCLI-FullTest
️✔️acr
️✔️latest
️✔️3.12
️✔️3.13
❌acs
❌latest
❌3.12
Type Test Case Error Message Line
Failed test_aks_create_with_acns_transit_encryption self = <azure.cli.testsdk.base.ExecutionResult object at 0x7fe1300a7fe0>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7fe131bfa660>
command = 'aks create --resource-group=clitest000001 --name=cliakstest000001 --location=westcentralus --ssh-key-value=/tmp/tmpjf...azure --network-dataplane=cilium --network-plugin-mode overlay --enable-acns --acns-transit-encryption-type WireGuard '
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:159: 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:678: in execute
    raise ex
src/azure-cli-core/azure/cli/core/commands/init.py:821: in run_jobs_serially
    results.append(self.run_job(expanded_arg, cmd_copy))
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:790: 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/acs/custom.py:1070: in aks_create
    return aks_create_decorator.create_mc(mc)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/acs/managed_cluster_decorator.py:7734: in create_mc
    cluster = self.put_mc(mc)
              ^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/acs/managed_cluster_decorator.py:7711: in put_mc
    cluster = sdk_no_wait(
src/azure-cli-core/azure/cli/core/util.py:794: 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/containerservice/operations/operations.py:3600: in begin_create_or_update
    raw_result = self.create_or_update_initial(
env/lib/python3.12/site-packages/azure/mgmt/containerservice/operations/operations.py:3423: 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:194: 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:375: 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 = <VCRRequestsHTTPSConnection/mnt/vss/work/1/s/src/azure-cli/azure/cli/command_modules/acs/tests/latest/recordings/test_aks_create_with_acns_transit_encryption.yaml(host='management.azure.com', port=443) at 0x7fe12ed10050>
 = 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/acs/tests/latest/recordings/test_aks_create_with_acns_transit_encryption.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/clitest000001/providers/Microsoft.ContainerService/managedClusters/cliakstest000001?api-version=2026-01-01>)&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/clitest000001/providers/Microsoft.ContainerService/managedClusters/cliakstest000001?api-version=2026-01-02-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:277: CannotOverwriteExistingCassetteException

During handling of the above exception, another exception occurred:

self = <azure.cli.command_modules.acs.tests.latest.test_aks_commands.AzureKubernetesServiceScenarioTest testMethod=test_aks_create_with_acns_transit_encryption>
resource_group = 'clitest000001', resource_group_location = 'westcentralus'

    @AllowLargeResponse()
    @AKSCustomResourceGroupPreparer(
        random_name_length=17,
        name_prefix="clitest",
        location="westcentralus",
    )
    def test_aks_create_with_acns_transit_encryption(
        self, resource_group, resource_group_location
    ):
        self.test_resources_count = 0
        aks_name = self.create_random_name("cliakstest", 16)
        self.kwargs.update(
            {
                "resource_group": resource_group,
                "name": aks_name,
                "ssh_key_value": self.generate_ssh_keys(),
                "location": resource_group_location,
            }
        )
    
        # create with ACNS and WireGuard transit encryption
        create_cmd = (
            "aks create --resource-group={resource_group} --name={name} --location={location} "
            "--ssh-key-value={ssh_key_value} --node-count=1 --tier standard "
            "--network-plugin azure --network-dataplane=cilium --network-plugin-mode overlay "
            "--enable-acns --acns-transit-encryption-type WireGuard "
        )
>       self.cmd(
            create_cmd,
            checks=[
                self.check("provisioningState", "Succeeded"),
                self.check("networkProfile.advancedNetworking.enabled", True),
                self.check("networkProfile.advancedNetworking.security.transitEncryption.type", "WireGuard"),
            ],
        )

src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_aks_commands.py:13459: 
 
 
 
 
 
 
                                  
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 0x7fe1300a7fe0>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7fe131bfa660>
command = 'aks create --resource-group=clitest000001 --name=cliakstest000001 --location=westcentralus --ssh-key-value=/tmp/tmpjf...azure --network-dataplane=cilium --network-plugin-mode overlay --enable-acns --acns-transit-encryption-type WireGuard '
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/acs/tests/latest/recordings/test_aks_create_with_acns_transit_encryption.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/clitest000001/providers/Microsoft.ContainerService/managedClusters/cliakstest000001?api-version=2026-01-01>)&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/clitest000001/providers/Microsoft.ContainerService/managedClusters/cliakstest000001?api-version=2026-01-02-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/acs/tests/latest/test_aks_commands.py:13431
Failed test_aks_update_acns_preserves_existing_settings The error message is too long, please check the pipeline log for details. azure/cli/command_modules/acs/tests/latest/test_aks_commands.py:13355
Failed test_aks_update_enable_acns The error message is too long, please check the pipeline log for details. azure/cli/command_modules/acs/tests/latest/test_aks_commands.py:12953
❌3.13
Type Test Case Error Message Line
Failed test_aks_create_with_acns_transit_encryption self = <azure.cli.testsdk.base.ExecutionResult object at 0x7feb32a02510>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7feb3494da90>
command = 'aks create --resource-group=clitest000001 --name=cliakstest000001 --location=westcentralus --ssh-key-value=/tmp/tmpbr...azure --network-dataplane=cilium --network-plugin-mode overlay --enable-acns --acns-transit-encryption-type WireGuard '
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:159: 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:678: in execute
    raise ex
src/azure-cli-core/azure/cli/core/commands/init.py:821: in run_jobs_serially
    results.append(self.run_job(expanded_arg, cmd_copy))
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:790: 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/acs/custom.py:1070: in aks_create
    return aks_create_decorator.create_mc(mc)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/acs/managed_cluster_decorator.py:7734: in create_mc
    cluster = self.put_mc(mc)
              ^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/acs/managed_cluster_decorator.py:7711: in put_mc
    cluster = sdk_no_wait(
src/azure-cli-core/azure/cli/core/util.py:794: 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/containerservice/operations/operations.py:3600: in begin_create_or_update
    raw_result = self.create_or_update_initial(
env/lib/python3.13/site-packages/azure/mgmt/containerservice/operations/operations.py:3423: 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:194: 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:375: 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 = <VCRRequestsHTTPSConnection/mnt/vss/work/1/s/src/azure-cli/azure/cli/command_modules/acs/tests/latest/recordings/test_aks_create_with_acns_transit_encryption.yaml(host='management.azure.com', port=443) at 0x7feb30574e10>
 = 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/acs/tests/latest/recordings/test_aks_create_with_acns_transit_encryption.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/clitest000001/providers/Microsoft.ContainerService/managedClusters/cliakstest000001?api-version=2026-01-01>)&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/clitest000001/providers/Microsoft.ContainerService/managedClusters/cliakstest000001?api-version=2026-01-02-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:277: CannotOverwriteExistingCassetteException

During handling of the above exception, another exception occurred:

self = <azure.cli.command_modules.acs.tests.latest.test_aks_commands.AzureKubernetesServiceScenarioTest testMethod=test_aks_create_with_acns_transit_encryption>
resource_group = 'clitest000001', resource_group_location = 'westcentralus'

    @AllowLargeResponse()
    @AKSCustomResourceGroupPreparer(
        random_name_length=17,
        name_prefix="clitest",
        location="westcentralus",
    )
    def test_aks_create_with_acns_transit_encryption(
        self, resource_group, resource_group_location
    ):
        self.test_resources_count = 0
        aks_name = self.create_random_name("cliakstest", 16)
        self.kwargs.update(
            {
                "resource_group": resource_group,
                "name": aks_name,
                "ssh_key_value": self.generate_ssh_keys(),
                "location": resource_group_location,
            }
        )
    
        # create with ACNS and WireGuard transit encryption
        create_cmd = (
            "aks create --resource-group={resource_group} --name={name} --location={location} "
            "--ssh-key-value={ssh_key_value} --node-count=1 --tier standard "
            "--network-plugin azure --network-dataplane=cilium --network-plugin-mode overlay "
            "--enable-acns --acns-transit-encryption-type WireGuard "
        )
>       self.cmd(
            create_cmd,
            checks=[
                self.check("provisioningState", "Succeeded"),
                self.check("networkProfile.advancedNetworking.enabled", True),
                self.check("networkProfile.advancedNetworking.security.transitEncryption.type", "WireGuard"),
            ],
        )

src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_aks_commands.py:13459: 
 
 
 
 
 
 
                                  
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 0x7feb32a02510>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7feb3494da90>
command = 'aks create --resource-group=clitest000001 --name=cliakstest000001 --location=westcentralus --ssh-key-value=/tmp/tmpbr...azure --network-dataplane=cilium --network-plugin-mode overlay --enable-acns --acns-transit-encryption-type WireGuard '
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/acs/tests/latest/recordings/test_aks_create_with_acns_transit_encryption.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/clitest000001/providers/Microsoft.ContainerService/managedClusters/cliakstest000001?api-version=2026-01-01>)&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/clitest000001/providers/Microsoft.ContainerService/managedClusters/cliakstest000001?api-version=2026-01-02-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/acs/tests/latest/test_aks_commands.py:13431
Failed test_aks_update_acns_preserves_existing_settings The error message is too long, please check the pipeline log for details. azure/cli/command_modules/acs/tests/latest/test_aks_commands.py:13355
Failed test_aks_update_enable_acns The error message is too long, please check the pipeline log for details. azure/cli/command_modules/acs/tests/latest/test_aks_commands.py:12953
️✔️advisor
️✔️latest
️✔️3.12
️✔️3.13
️✔️ams
️✔️latest
️✔️3.12
️✔️3.13
️✔️apim
️✔️latest
️✔️3.12
️✔️3.13
️✔️appconfig
️✔️latest
️✔️3.12
️✔️3.13
️✔️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
️✔️postgresql
️✔️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
️✔️3.13
️✔️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
Copy Markdown

Hi @nddq,
Since the current milestone time is less than 7 days, this pr will be reviewed in the next milestone.

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

azure-client-tools-bot-prd bot commented Mar 25, 2026

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

@yonzhan
Copy link
Copy Markdown
Collaborator

yonzhan commented Mar 25, 2026

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

@github-actions
Copy link
Copy Markdown

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>

Copy link
Copy Markdown
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 addresses an AKS update-path issue where partial ACNS updates could unintentionally drop existing advancedNetworking sub-settings by replacing the entire AdvancedNetworking object, instead of updating only user-specified fields.

Changes:

  • Update decorator logic to mutate mc.network_profile.advanced_networking in-place and only overwrite explicitly provided ACNS fields.
  • Add/extend unit tests to validate partial updates preserve existing ACNS state.
  • Add a live test that performs sequential partial updates (network policies, then transit encryption) and verifies settings persist.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/azure-cli/azure/cli/command_modules/acs/managed_cluster_decorator.py Switches ACNS update logic from “replace object” to “mutate existing object” for partial updates.
src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_managed_cluster_decorator.py Adds unit coverage for preserving existing ACNS sub-properties across partial updates.
src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_aks_commands.py Adds a live test ensuring sequential partial ACNS updates preserve previously-set values.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@nddq nddq force-pushed the fix/acns-update-preserve-existing-state-v2 branch from 22be663 to 37d1788 Compare March 25, 2026 22:58
@FumingZhang
Copy link
Copy Markdown
Member

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 3 pipeline(s).

Copy link
Copy Markdown
Member

@FumingZhang FumingZhang left a comment

Choose a reason for hiding this comment

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

Please update the PR title or description to meet the required history note format so the CI check can pass.

User-Agent:
- AZURECLI/2.84.0 azsdk-python-core/1.38.3 Python/3.12.3 (Linux-6.17.0-1008-azure-x86_64-with-glibc2.39)
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest000001/providers/Microsoft.ContainerService/managedClusters/cliakstest000001?api-version=2025-10-02-preview
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The recording file is outdated—the API version used is 2025-10-02-preview, but it should be a stable API version, which is now 2026-01-01. Please generate a new recording file.

name_prefix="clitest",
location="westcentralus",
)
def test_aks_update_acns_preserves_existing_settings(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Queued live test to validate the change.

  • test_aks_update_acns_preserves_existing_settings

You might consider running the test with other related existing test cases to make sure the change doesn't cause any regression.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Re-queued live test

User-Agent:
- AZURECLI/2.84.0 azsdk-python-core/1.38.3 Python/3.12.3 (Linux-6.17.0-1008-azure-x86_64-with-glibc2.39)
method: GET
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest000001/providers/Microsoft.ContainerService/managedClusters/cliakstest000001?api-version=2025-10-02-preview
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The recording file is outdated—the API version used is 2025-10-02-preview, but it should be a stable API version, which is now 2026-01-01. Please generate a new recording file.

@nddq nddq force-pushed the fix/acns-update-preserve-existing-state-v2 branch from 37d1788 to fdb827a Compare March 26, 2026 02:15
The update_network_profile_advanced_networking method was creating a
new AdvancedNetworking object on every update, discarding existing
sub-properties (observability, security, transit encryption) that the
user didn't explicitly specify. This changes the method to modify the
existing object in-place, only overwriting fields the user provided.
When disabling ACNS, sub-features are explicitly set to disabled to
ensure a consistent payload.

Signed-off-by: Quang Nguyen <nguyenquang@microsoft.com>
@nddq nddq force-pushed the fix/acns-update-preserve-existing-state-v2 branch from fdb827a to e8ddb8e Compare March 26, 2026 02:31
@FumingZhang
Copy link
Copy Markdown
Member

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 3 pipeline(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

act-observability-squad AKS az aks/acs/openshift Auto-Assign Auto assign by bot

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants