Conversation
❌Azure CLI Extensions Breaking Change Test
|
|
Hi @frantran, |
|
Thank you for your contribution! We will review the pull request and get back to you soon. |
|
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). pip install azdev --upgrade
azdev setup -c <your azure-cli repo path> -r <your azure-cli-extensions repo path>
|
src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/aio/_configuration.py
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
This PR updates the fleet extension to the 2026-03-02-preview Fleet management API, refreshes the vendored SDK accordingly, and introduces new CLI surface area for managing Cluster Mesh Profiles (including a what-if style preview of membership changes).
Changes:
- Bump extension version to
2.0.0and updateHISTORY.rstfor the new preview API. - Vendor the
v2026_03_02_previewmanagement SDK and wire it up as the extension’s “latest” client. - Add new
az fleet clustermeshprofilecommand group plus member filtering support via$filter.
Reviewed changes
Copilot reviewed 51 out of 57 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/fleet/setup.py | Bumps extension package version to 2.0.0. |
| src/fleet/HISTORY.rst | Adds 2.0.0 release notes for 2026-03-02-preview / ClusterMesh support. |
| src/fleet/azext_fleet/custom.py | Adds cluster mesh profile commands, what-if logic, and member list filtering. |
| src/fleet/azext_fleet/commands.py | Registers new fleet clustermeshprofile command group. |
| src/fleet/azext_fleet/_params.py | Adds parameters for cluster mesh profile commands and member filtering. |
| src/fleet/azext_fleet/_help.py | Adds help + examples for new commands and new filter option. |
| src/fleet/azext_fleet/_client_factory.py | Updates mgmt client creation (now explicitly sets base_url). |
| src/fleet/azext_fleet/init.py | Updates resource type registration to use no SDK profile mapping. |
| src/fleet/azext_fleet/tests/latest/test_stages_json.py | Updates test imports to v2026_03_02_preview models. |
| src/fleet/azext_fleet/vendored_sdks/init.py | Points vendored SDK to v2026_03_02_preview and aliases models/operations modules. |
| src/fleet/azext_fleet/vendored_sdks/models.py | Removes old re-export shim for v2026_02_01_preview models. |
| src/fleet/azext_fleet/vendored_sdks/_version.py | Removes old SDK version file at vendored_sdks root. |
| src/fleet/azext_fleet/vendored_sdks/_container_service_fleet_mgmt_client.py | Removes old multi-api client implementation. |
| src/fleet/azext_fleet/vendored_sdks/_configuration.py | Removes old shared configuration. |
| src/fleet/azext_fleet/vendored_sdks/v2026_02_01_preview/py.typed | Removes typing marker from previous preview package. |
| src/fleet/azext_fleet/vendored_sdks/v2026_02_01_preview/operations/_patch.py | Removes generated patch file from previous preview package. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/py.typed | Adds PEP 561 typing marker for new preview package. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/_serialization.py | Adds/updates shared serialization module used by generated code. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/_patch.py | Adds generated patch hook module. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/init.py | Adds package init for new preview SDK. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/_version.py | Adds new preview SDK version constant. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/_utils/init.py | Adds generated utils package init. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/_container_service_fleet_mgmt_client.py | Adds ClusterMeshProfiles operations + updates base_url handling and api_version default. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/_configuration.py | Updates default api_version to 2026-03-02-preview and simplifies config. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/models/_patch.py | Updates generated models patch module typing. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/models/_models_py3.py | Adds ClusterMesh models + MeshProperties on FleetMember; updates typing + serialization import. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/models/_container_service_fleet_mgmt_client_enums.py | Adds ClusterMesh-related enums. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/models/init.py | Exposes new ClusterMesh models/enums from package. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/operations/_update_runs_operations.py | Updates api-version default and serialization import; typing cleanups. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/operations/_operations.py | Updates api-version default and serialization import; typing cleanups. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/operations/_gates_operations.py | Updates api-version default and serialization import; typing cleanups. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/operations/_fleets_operations.py | Updates api-version default and serialization import; typing cleanups. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/operations/_fleet_update_strategies_operations.py | Updates api-version default and serialization import; typing cleanups. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/operations/_fleet_members_operations.py | Adds $filter support to list-by-fleet; updates api-version default. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/operations/_fleet_managed_namespaces_operations.py | Updates api-version default and serialization import; typing cleanups. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/operations/_auto_upgrade_profiles_operations.py | Updates api-version default and serialization import; typing cleanups. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/operations/_auto_upgrade_profile_operations_operations.py | Updates api-version default and serialization import; typing cleanups. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/operations/_patch.py | Adds generated operations patch hook module. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/operations/_cluster_mesh_profiles_operations.py | Adds new ClusterMeshProfiles operation group (sync). |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/operations/init.py | Exports ClusterMeshProfilesOperations. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/aio/init.py | Adds async client package init. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/aio/_patch.py | Updates async patch hook typing. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/aio/_configuration.py | Updates async config default api_version to 2026-03-02-preview. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/aio/_container_service_fleet_mgmt_client.py | Adds ClusterMeshProfiles operations + updates base_url handling (async). |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/aio/operations/_update_runs_operations.py | Updates serialization import + typing; api-version alignment. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/aio/operations/_operations.py | Updates serialization import + typing; api-version alignment. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/aio/operations/_gates_operations.py | Updates serialization import + typing; api-version alignment. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/aio/operations/_fleets_operations.py | Updates serialization import + typing; api-version alignment. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/aio/operations/_fleet_update_strategies_operations.py | Updates serialization import + typing; api-version alignment. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/aio/operations/_fleet_members_operations.py | Updates serialization import + typing; supports list-by-fleet filtering. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/aio/operations/_fleet_managed_namespaces_operations.py | Updates serialization import + typing; api-version alignment. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/aio/operations/_auto_upgrade_profiles_operations.py | Updates serialization import + typing; api-version alignment. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/aio/operations/_auto_upgrade_profile_operations_operations.py | Updates serialization import + typing; api-version alignment. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/aio/operations/_patch.py | Updates async operations patch hook typing. |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/aio/operations/_cluster_mesh_profiles_operations.py | Adds new ClusterMeshProfiles operation group (async). |
| src/fleet/azext_fleet/vendored_sdks/v2026_03_02_preview/aio/operations/init.py | Exports async ClusterMeshProfilesOperations. |
| members_client = cf_fleet_members(cmd.cli_ctx) | ||
| if selector: | ||
| filter_expr = f"clusterMeshProfile.Selector eq {name}" | ||
| else: | ||
| filter_expr = f"clusterMeshProfile eq {name}" | ||
| return members_client.list_by_fleet(resource_group_name, fleet_name, filter=filter_expr) |
There was a problem hiding this comment.
Cluster mesh member filtering builds $filter expressions without quoting the mesh profile name. These comparisons are against string fields, so the value should be quoted (and escaped) to avoid invalid OData syntax and incorrect server-side filtering.
| # Members currently in the mesh (already applied) | ||
| current_filter = f"clusterMeshProfile eq {name}" | ||
| current_members = { | ||
| m.name: m for m in members_client.list_by_fleet( | ||
| resource_group_name, fleet_name, filter=current_filter | ||
| ) | ||
| } | ||
|
|
||
| # Members that match the selector (would be in the mesh after apply) | ||
| selector_filter = f"clusterMeshProfile.Selector eq {name}" | ||
| desired_members = { | ||
| m.name: m for m in members_client.list_by_fleet( | ||
| resource_group_name, fleet_name, filter=selector_filter | ||
| ) |
There was a problem hiding this comment.
The what-if implementation also constructs $filter values without quoting the mesh profile name. This will likely break the list calls (and can change semantics if the name contains special characters). Quote/escape the value consistently with the other filter usage.
| FLEET_BASE_URL = "https://management.azure.com" | ||
|
|
||
|
|
||
| # container service clients | ||
| def get_container_service_client(cli_ctx, subscription_id=None): | ||
| return get_mgmt_service_client(cli_ctx, CUSTOM_MGMT_FLEET, subscription_id=subscription_id) | ||
| return get_mgmt_service_client( | ||
| cli_ctx, CUSTOM_MGMT_FLEET, | ||
| subscription_id=subscription_id, | ||
| base_url_bound=False, | ||
| base_url=FLEET_BASE_URL | ||
| ) |
There was a problem hiding this comment.
FLEET_BASE_URL is hard-coded to the public Azure Resource Manager endpoint. This will break the extension in sovereign clouds (Azure Government/China/Stack) where the ARM endpoint differs. Prefer deriving the base URL from cli_ctx.cloud.endpoints.resource_manager (or letting get_mgmt_service_client supply it) instead of a constant.
| def create_cluster_mesh_profile(cmd, | ||
| client, | ||
| resource_group_name, | ||
| fleet_name, | ||
| name, | ||
| member_selector=None, | ||
| no_wait=False): | ||
| cluster_mesh_profile_model = cmd.get_models( | ||
| "ClusterMeshProfile", | ||
| resource_type=CUSTOM_MGMT_FLEET, | ||
| operation_group="cluster_mesh_profiles" | ||
| ) | ||
| cluster_mesh_profile_properties_model = cmd.get_models( | ||
| "ClusterMeshProfileProperties", | ||
| resource_type=CUSTOM_MGMT_FLEET, | ||
| operation_group="cluster_mesh_profiles" | ||
| ) | ||
| member_selector_model = cmd.get_models( | ||
| "MemberSelector", | ||
| resource_type=CUSTOM_MGMT_FLEET, | ||
| operation_group="cluster_mesh_profiles" | ||
| ) | ||
|
|
||
| selector = None | ||
| if member_selector is not None: | ||
| selector = member_selector_model(by_label=member_selector) | ||
|
|
||
| properties = cluster_mesh_profile_properties_model(member_selector=selector) | ||
| profile = cluster_mesh_profile_model(properties=properties) | ||
|
|
||
| return sdk_no_wait( | ||
| no_wait, | ||
| client.begin_create_or_update, | ||
| resource_group_name, | ||
| fleet_name, | ||
| name, | ||
| profile | ||
| ) | ||
|
|
||
|
|
||
| def show_cluster_mesh_profile(cmd, # pylint: disable=unused-argument | ||
| client, | ||
| resource_group_name, | ||
| fleet_name, | ||
| name): | ||
| return client.get(resource_group_name, fleet_name, name) | ||
|
|
||
|
|
||
| def list_cluster_mesh_profiles(cmd, # pylint: disable=unused-argument | ||
| client, | ||
| resource_group_name, | ||
| fleet_name): | ||
| return client.list_by_fleet(resource_group_name, fleet_name) | ||
|
|
||
|
|
||
| def delete_cluster_mesh_profile(cmd, # pylint: disable=unused-argument | ||
| client, | ||
| resource_group_name, | ||
| fleet_name, | ||
| name, | ||
| no_wait=False): | ||
| return sdk_no_wait(no_wait, client.begin_delete, resource_group_name, fleet_name, name) | ||
|
|
||
|
|
||
| def apply_cluster_mesh_profile(cmd, | ||
| client, | ||
| resource_group_name, | ||
| fleet_name, | ||
| name, | ||
| what_if=False, | ||
| no_wait=False): | ||
| if what_if: | ||
| return _apply_cluster_mesh_what_if(cmd, resource_group_name, fleet_name, name) | ||
|
|
||
| return sdk_no_wait(no_wait, client.begin_apply, resource_group_name, fleet_name, name) | ||
|
|
There was a problem hiding this comment.
New cluster mesh profile commands and the --what-if diff logic introduce non-trivial behavior (model construction, server-side filtering, and client-side diffing) but there are no accompanying tests under azext_fleet/tests/latest to validate it. Adding unit tests for filter construction/quoting and basic what-if diff output would help prevent regressions.
| cluster_mesh_profile=None): | ||
| filter_expr = None | ||
| if cluster_mesh_profile: | ||
| filter_expr = f"clusterMeshProfile eq {cluster_mesh_profile}" |
There was a problem hiding this comment.
The OData $filter expression for --cluster-mesh-profile is constructed without quoting the profile name. For string comparisons, the value should be quoted (and any embedded quotes escaped), otherwise requests may fail or the filter could be parsed incorrectly.
| filter_expr = f"clusterMeshProfile eq {cluster_mesh_profile}" | |
| escaped_profile = str(cluster_mesh_profile).replace("'", "''") | |
| filter_expr = f"clusterMeshProfile eq '{escaped_profile}'" |
|
Hi @frantran
|
|
/azp run |
|
Azure Pipelines successfully started running 2 pipeline(s). |
This checklist is used to make sure that common guidelines for a pull request are followed.
Related command
General Guidelines
azdev style <YOUR_EXT>locally? (pip install azdevrequired)python scripts/ci/test_index.py -qlocally? (pip install wheel==0.30.0required)For new extensions:
About Extension Publish
There is a pipeline to automatically build, upload and publish extension wheels.
Once your pull request is merged into main branch, a new pull request will be created to update
src/index.jsonautomatically.You only need to update the version information in file setup.py and historical information in file HISTORY.rst in your PR but do not modify
src/index.json.