Skip to content

Commit dbf7af8

Browse files
author
indusridhar
committed
Add nodepool rollback and get-rollback-versions commands
1 parent cfaf118 commit dbf7af8

File tree

7 files changed

+382
-0
lines changed

7 files changed

+382
-0
lines changed

src/aks-preview/HISTORY.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ To release a new version, please select a new version number (usually plus 1 to
1111

1212
Pending
1313
+++++++
14+
* `az aks nodepool get-rollback-versions`: New command to get available rollback versions for an agent pool.
15+
* `az aks nodepool rollback`: New command to rollback an agent pool to the most recently used configuration (N-1).
1416

1517
19.0.0b20
1618
+++++++

src/aks-preview/azext_aks_preview/_format.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,18 @@ def aks_agentpool_list_table_format(results):
153153
return [_aks_agentpool_table_format(r) for r in results]
154154

155155

156+
def aks_agentpool_rollback_versions_table_format(results):
157+
"""Format rollback versions for display with "-o table"."""
158+
if not results:
159+
return []
160+
161+
def _format_rollback_version(result):
162+
parsed = compile_jmes("""{\n kubernetesVersion: orchestrator_version,\n nodeImageVersion: node_image_version,\n timestamp: timestamp\n }""")
163+
return parsed.search(result, Options(dict_cls=OrderedDict))
164+
165+
return [_format_rollback_version(r) for r in results]
166+
167+
156168
def aks_list_table_format(results):
157169
""""Format a list of managed clusters as summary results for display with "-o table"."""
158170
return [_aks_table_format(r) for r in results]

src/aks-preview/azext_aks_preview/_help.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2466,6 +2466,40 @@
24662466
crafted: true
24672467
"""
24682468

2469+
helps['aks nodepool get-rollback-versions'] = """
2470+
type: command
2471+
short-summary: Get the available rollback versions for an agent pool of the managed Kubernetes cluster.
2472+
long-summary: |
2473+
Get the list of historically used Kubernetes and node image versions that can be used for rollback operations.
2474+
examples:
2475+
- name: Get the available rollback versions for an agent pool.
2476+
text: az aks nodepool get-rollback-versions --resource-group MyResourceGroup --cluster-name MyManagedCluster --nodepool-name MyNodePool
2477+
crafted: true
2478+
"""
2479+
2480+
helps['aks nodepool rollback'] = """
2481+
type: command
2482+
short-summary: Rollback an agent pool to the most recently used configuration (N-1).
2483+
long-summary: |
2484+
Rollback an agent pool to the most recently used version based on rollback history.
2485+
This will rollback both the Kubernetes version and node image version to their most recent previous state.
2486+
For downgrades to older versions (N-2 or earlier), use a separate downgrade operation.
2487+
parameters:
2488+
- name: --aks-custom-headers
2489+
type: string
2490+
short-summary: Send custom headers. When specified, format should be Key1=Value1,Key2=Value2.
2491+
- name: --if-match
2492+
type: string
2493+
short-summary: The revision of the resource being updated. This should match the current revision.
2494+
- name: --if-none-match
2495+
type: string
2496+
short-summary: Set to '*' to allow a new resource to be created, but to prevent updating an existing resource.
2497+
examples:
2498+
- name: Rollback a nodepool to the most recently used version.
2499+
text: az aks nodepool rollback --resource-group MyResourceGroup --cluster-name MyManagedCluster --nodepool-name MyNodePool
2500+
crafted: true
2501+
"""
2502+
24692503
helps['aks nodepool stop'] = """
24702504
type: command
24712505
short-summary: Stop running agent pool in the managed Kubernetes cluster.

src/aks-preview/azext_aks_preview/_params.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2199,6 +2199,14 @@ def load_arguments(self, _):
21992199
with self.argument_context("aks nodepool manual-scale delete") as c:
22002200
c.argument("current_vm_sizes", is_preview=True)
22012201

2202+
with self.argument_context("aks nodepool get-rollback-versions") as c:
2203+
pass # Uses common nodepool parameters
2204+
2205+
with self.argument_context("aks nodepool rollback") as c:
2206+
c.argument("aks_custom_headers", nargs="*")
2207+
c.argument("if_match")
2208+
c.argument("if_none_match")
2209+
22022210
with self.argument_context("aks machine") as c:
22032211
c.argument("cluster_name", help="The cluster name.")
22042212
c.argument(

src/aks-preview/azext_aks_preview/commands.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
aks_addon_show_table_format,
2727
aks_agentpool_list_table_format,
2828
aks_agentpool_show_table_format,
29+
aks_agentpool_rollback_versions_table_format,
2930
aks_machine_list_table_format,
3031
aks_machine_show_table_format,
3132
aks_operation_show_table_format,
@@ -274,6 +275,12 @@ def load_command_table(self, _):
274275
g.custom_command("update", "aks_agentpool_update", supports_no_wait=True)
275276
g.custom_command("delete", "aks_agentpool_delete", supports_no_wait=True)
276277
g.custom_command("get-upgrades", "aks_agentpool_get_upgrade_profile")
278+
g.custom_command(
279+
"get-rollback-versions",
280+
"aks_agentpool_get_rollback_versions",
281+
table_transformer=aks_agentpool_rollback_versions_table_format
282+
)
283+
g.custom_command("rollback", "aks_agentpool_rollback", supports_no_wait=True)
277284
g.custom_command("stop", "aks_agentpool_stop", supports_no_wait=True)
278285
g.custom_command("start", "aks_agentpool_start", supports_no_wait=True)
279286
g.custom_command(

src/aks-preview/azext_aks_preview/custom.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2222,6 +2222,114 @@ def aks_agentpool_get_upgrade_profile(cmd, # pylint: disable=unused-argument
22222222
return client.get_upgrade_profile(resource_group_name, cluster_name, nodepool_name)
22232223

22242224

2225+
def aks_agentpool_get_rollback_versions(cmd, # pylint: disable=unused-argument
2226+
client,
2227+
resource_group_name,
2228+
cluster_name,
2229+
nodepool_name):
2230+
"""Get rollback versions for a nodepool."""
2231+
upgrade_profile = client.get_upgrade_profile(resource_group_name, cluster_name, nodepool_name)
2232+
return upgrade_profile.recently_used_versions
2233+
2234+
2235+
def aks_agentpool_rollback(cmd, # pylint: disable=unused-argument
2236+
client,
2237+
resource_group_name,
2238+
cluster_name,
2239+
nodepool_name,
2240+
aks_custom_headers=None,
2241+
if_match=None,
2242+
if_none_match=None,
2243+
no_wait=False):
2244+
"""Rollback a nodepool to the most recent previous version configuration."""
2245+
from azext_aks_preview._client_factory import cf_managed_clusters
2246+
2247+
# Warn users when auto-upgrade is enabled
2248+
if cmd and getattr(cmd, "cli_ctx", None):
2249+
try:
2250+
managed_clusters_client = cf_managed_clusters(cmd.cli_ctx)
2251+
managed_cluster = managed_clusters_client.get(resource_group_name, cluster_name)
2252+
auto_upgrade_profile = getattr(managed_cluster, "auto_upgrade_profile", None)
2253+
2254+
upgrade_channel = getattr(auto_upgrade_profile, "upgrade_channel", None) if auto_upgrade_profile else None
2255+
node_os_upgrade_channel = (
2256+
getattr(auto_upgrade_profile, "node_os_upgrade_channel", None)
2257+
if auto_upgrade_profile
2258+
else None
2259+
)
2260+
2261+
upgrade_channel_enabled = upgrade_channel and str(upgrade_channel).lower() != "none"
2262+
node_os_channel_enabled = node_os_upgrade_channel and str(node_os_upgrade_channel).lower() not in [
2263+
"none",
2264+
"unmanaged",
2265+
]
2266+
2267+
if upgrade_channel_enabled or node_os_channel_enabled:
2268+
logger.warning(
2269+
"Auto-upgrade is enabled on cluster '%s' (upgradeChannel=%s, nodeOSUpgradeChannel=%s). "
2270+
"Rollback will not succeed until auto-upgrade is disabled. Please disable auto-upgrade to roll back the node pool.",
2271+
cluster_name,
2272+
upgrade_channel or "none",
2273+
node_os_upgrade_channel or "Unmanaged",
2274+
)
2275+
except Exception as ex: # pylint: disable=broad-except
2276+
logger.debug("Unable to retrieve auto-upgrade configuration before rollback: %s", ex)
2277+
2278+
logger.info("Fetching the most recent rollback version...")
2279+
2280+
# Get upgrade profile to retrieve recently used versions
2281+
upgrade_profile = client.get_upgrade_profile(resource_group_name, cluster_name, nodepool_name)
2282+
2283+
if not upgrade_profile.recently_used_versions or len(upgrade_profile.recently_used_versions) == 0:
2284+
raise CLIError(
2285+
"No rollback versions available. The nodepool must have been upgraded at least once "
2286+
"to have rollback history available."
2287+
)
2288+
2289+
# Sort by timestamp (most recent first) and get the most recent version
2290+
sorted_versions = sorted(
2291+
upgrade_profile.recently_used_versions,
2292+
key=lambda v: v.timestamp if v.timestamp else datetime.datetime.min,
2293+
reverse=True
2294+
)
2295+
most_recent = sorted_versions[0]
2296+
2297+
kubernetes_version = most_recent.orchestrator_version
2298+
node_image_version = most_recent.node_image_version
2299+
2300+
logger.info(
2301+
"Rolling back to the most recent version: "
2302+
"Kubernetes version: %s, Node image version: %s (timestamp: %s)",
2303+
kubernetes_version, node_image_version, most_recent.timestamp
2304+
)
2305+
2306+
# Get the current agent pool
2307+
current_agentpool = client.get(resource_group_name, cluster_name, nodepool_name)
2308+
2309+
# Update the agent pool configuration with rollback versions
2310+
current_agentpool.orchestrator_version = kubernetes_version
2311+
current_agentpool.node_image_version = node_image_version
2312+
2313+
# Set custom headers if provided
2314+
headers = get_aks_custom_headers(aks_custom_headers)
2315+
if if_match:
2316+
headers['If-Match'] = if_match
2317+
if if_none_match:
2318+
headers['If-None-Match'] = if_none_match
2319+
2320+
# Perform the rollback by updating the agent pool
2321+
# Server-side will validate the versions
2322+
return sdk_no_wait(
2323+
no_wait,
2324+
client.begin_create_or_update,
2325+
resource_group_name,
2326+
cluster_name,
2327+
nodepool_name,
2328+
current_agentpool,
2329+
headers=headers if headers else None
2330+
)
2331+
2332+
22252333
def aks_agentpool_stop(cmd, # pylint: disable=unused-argument
22262334
client,
22272335
resource_group_name,

0 commit comments

Comments
 (0)