Azure / Azure/azure-cli

az vmss update retains the previous zone placement filter when switching between --include-zones and --exclude-zones

Open
#34,063 1 comment 0 reactions 1 assignee Claimed by @yanzhudd View on GitHub
act-observability-squad Auto-Assign Azure CLI Team bug Compute customer-reported
Dominant language
Python
Stars
4.6k
Forks
3.5k
Avg merge
3d 2h
Merged PRs (30d)
60

Description

### Describe the bug

A VM Scale Set can persist either `placement.includeZones` or `placement.excludeZones`. When `az vmss update` is used to switch to the opposite filter, Azure CLI preserves the filter loaded from the existing VMSS and adds the newly requested filter.

For example:

1. The VMSS currently has `placement.includeZones`.
2. The user runs `az vmss update` with only `--exclude-zones`.
3. Generic update retains the existing `includeZones` value and adds `excludeZones`.
4. The model passed to the final VMSS create-or-update operation contains both mutually exclusive properties.

The reverse transition—existing `excludeZones` followed by `--include-zones`—has the same defect.

### Actual behavior

A deterministic test of the real update handler observed both properties at the final `VMSSCreate(command_args=...)` boundary:

```python
{
"zone_placement_policy": "Auto",
"include_zones": ["1"],
"exclude_zones": ["2"],
}
```

The current validator rejects both flags when they are supplied in one invocation, but it cannot see an opposite filter already present in the VMSS state loaded by generic update.

### Related command

`az vmss update`

### Errors

A live Azure request was not performed during this investigation, so no local service error or `--debug` log was captured.

Azure/azure-cli#33473 documents the Compute response when both properties are sent:

```text
BadRequest: Both 'placement.includeZones' and 'placement.excludeZones' cannot be set.
```

### Issue script & Debug output

This was verified deterministically against current `dev` at commit `8bead7f93f086629efb160d56c25f508156925bf`.

The regression test supplies an existing VMSS response containing one camelCase placement filter, invokes the actual `update_vmss` handler with only the opposite snake_case argument, mocks the final `VMSSCreate` operation boundary, and inspects the complete `command_args`. Both transition directions are covered.

Test command:

```bash
PYTHONPATH=src/azure-cli:src/azure-cli-core:src/azure-cli-testsdk \
python -m unittest \
azure.cli.command_modules.vm.tests.latest.test_custom_vm_commands.TestVmCustom.test_update_vmss_switches_zone_placement_filter
```

Before changing production code:

```text
FF
Ran 1 test
FAILED (failures=2)
```

The failures specifically showed the stale opposite filter still present in the model passed to `VMSSCreate`. After the two-line normalization fix, the same test passes in both directions; the canonical `azdev` run reports `1 passed, 2 subtests passed`.

Proposed test/fix commit: https://github.com/ryo-whaletech/azure-cli/commit/8f26c3f182c7f1dbd0b3adfd3d7e486c9d32791b

No live `--debug` output is available; no Azure resources were changed for this source-level reproduction.

### Expected behavior

Updating a VMSS from one zone placement filter to the other should not cause Azure CLI to send both mutually exclusive placement filters in the same request.

### Environment Summary

### Latest released version affected by source inspection

```text
azure-cli 2.90.0
core 2.90.0
telemetry 1.1.0
Extensions: None
```

The `azure-cli-2.90.0` source tag (`dc50d475a00ded4a1a1980d4a10a9fbd9a750a81`) contains the same stale-filter update logic. This is source inspection only; a packaged 2.90.0 live failure was not claimed.

### Development verification

```text
Repository: Azure/azure-cli
Branch: dev
Commit: 8bead7f93f086629efb160d56c25f508156925bf
Python: 3.13.11
OS: macOS 26.6.2 arm64
```

### Live reproduction environment

Not performed. No usable authenticated disposable Azure VMSS environment was available, so no live transition or sanitized `--debug` capture is included.

### Additional context

- #31951 is the earlier overall Automatic Zone Placement feature request.
- #33473 documents that `includeZones` and `excludeZones` are mutually exclusive.
- #33474 requests update support for these placement fields.
- #33639 implements update support and same-invocation validation, but independently assigns the new fields and does not cover transitions from persisted opposite state.
- #33915 is a closed, unmerged draft revert of the entire update feature; it is not a fix for this transition defect.
- Existing coverage sets include and exclude filters independently, but does not switch an existing VMSS from one filter to the other.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.