Skip to content

Commit e392506

Browse files
authored
[Redisenterprise] az redisenterprise update: Unset capacity and zones while updating sku from enterprise to azure mananaged redis skus as they don't support the properties (#9529)
* Fix Redis Enterprise SKU update and zone configuration issues * Add examples for redisenterprise update command to fix linting error * Add flashoptimized in sku check * remove spaces * remove spaces * update helper in aaz registration * update version
1 parent 342d236 commit e392506

File tree

8 files changed

+3694
-1
lines changed

8 files changed

+3694
-1
lines changed

src/redisenterprise/HISTORY.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
33
Release History
44
===============
5+
1.3.1
6+
- Fixed an issue where updating sku from Azure Cache for Enterprise to Azure Managed Redis SKU was not working as expected.
7+
58
1.3.0
69
- Added a new required property: PublicNetworkAccess for Cluster.
710
- Updated the default value of AccessKeysAuthentication property for Database to 'Disabled'.

src/redisenterprise/azext_redisenterprise/aaz/latest/redisenterprise/_update.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
)
1717
class Update(AAZCommand):
1818
"""Update an existing (overwrite/recreate, with potential downtime) cache cluster
19+
20+
:example: Updates cluster SKU
21+
az redisenterprise update --cluster-name "cache1" --sku "ComputeOptimized_X5" --resource-group "rg1"
1922
"""
2023

2124
_aaz_info = {

src/redisenterprise/azext_redisenterprise/commands.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ def load_command_table(self, _): # pylint: disable=unused-argument
1616
g.custom_command('create', 'redisenterprise_create', supports_no_wait=True)
1717
g.custom_command('list', 'redisenterprise_list')
1818
g.custom_show_command('show', 'redisenterprise_show')
19+
from .custom import RedisEnterpriseUpdate
20+
self.command_table["redisenterprise update"] = RedisEnterpriseUpdate(loader=self)
1921
with self.command_group("redisenterprise database"):
2022
from .custom import DatabaseFlush, DatabaseCreate, DatabaseDelete, DatabaseExport, DatabaseForceUnlink
2123
from .custom import DatabaseImport, DatabaseListKey, DatabaseRegenerateKey

src/redisenterprise/azext_redisenterprise/custom.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,51 @@
2424
from .aaz.latest.redisenterprise import List as _ClusterList
2525
from .aaz.latest.redisenterprise import Show as _ClusterShow
2626
from .aaz.latest.redisenterprise import Wait as _DatabaseWait
27+
from .aaz.latest.redisenterprise import Update as _Update
2728
from azure.cli.core.azclierror import (
2829
MutuallyExclusiveArgumentError,
2930
)
3031

3132
logger = get_logger(__name__)
3233

3334

35+
class RedisEnterpriseUpdate(_Update):
36+
37+
def pre_instance_update(self, instance):
38+
"""Called before the instance is updated"""
39+
try:
40+
current_sku = str(instance.sku.name) if hasattr(instance, 'sku') and instance.sku else None
41+
except (AttributeError, TypeError):
42+
current_sku = None
43+
44+
new_sku = str(self.ctx.args.sku) if self.ctx.args.sku is not None else None
45+
46+
if new_sku and current_sku and new_sku != current_sku:
47+
self._handle_sku_change(current_sku, new_sku, instance)
48+
49+
def _handle_sku_change(self, current_sku, new_sku, instance):
50+
"""Handle SKU change logic for capacity and zones"""
51+
# Check if changing from Azure Cache for Redis Enterprise to Azure Managed Redis SKU types
52+
# that don't support capacity/zones
53+
if (current_sku.startswith('Enterprise') and
54+
(new_sku.startswith('Balanced_') or
55+
new_sku.startswith('ComputeOptimized_') or
56+
new_sku.startswith('MemoryOptimized_') or
57+
new_sku.startswith('FlashOptimized_'))):
58+
# Unset capacity and zones in the instance
59+
try:
60+
if hasattr(instance, 'sku') and instance.sku and hasattr(instance.sku, 'capacity'):
61+
instance.sku.capacity = None
62+
except (AttributeError, TypeError):
63+
pass
64+
65+
try:
66+
if hasattr(instance, 'zones'):
67+
instance.zones = None
68+
except (AttributeError, TypeError):
69+
pass
70+
71+
3472
class DatabaseFlush(_DatabaseFlush):
3573

3674
@classmethod

src/redisenterprise/azext_redisenterprise/tests/latest/example_steps.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,21 @@ def step_create(test, checks=None, cache_num=1):
9797
'--port 10000 '
9898
'--resource-group "{rg}"',
9999
checks=checks)
100+
elif test.kwargs.get('sku-update'):
101+
test.cmd('az redisenterprise create '
102+
'--cluster-name "{cluster}" '
103+
'--sku "{initial_sku}" '
104+
'--location "centraluseuap" '
105+
'--tags tag1="value1" '
106+
'--minimum-tls-version "1.2" '
107+
'--client-protocol "Encrypted" '
108+
'--clustering-policy "EnterpriseCluster" '
109+
'--public-network-access "Enabled" '
110+
'--access-keys-auth Enabled '
111+
'--eviction-policy "NoEviction" '
112+
'--port 10000 '
113+
'--resource-group "{rg}"',
114+
checks=checks)
100115
else:
101116
test.cmd('az redisenterprise create '
102117
'--cluster-name "{cluster}" '
@@ -165,6 +180,16 @@ def step_delete(test, checks=None):
165180
'--resource-group "{rg}"',
166181
checks=checks)
167182

183+
def step_update(test, checks=None):
184+
if checks is None:
185+
checks = []
186+
if test.kwargs.get('sku-update'):
187+
test.cmd('az redisenterprise update '
188+
'--cluster-name "{cluster}" '
189+
'--sku "{new_sku}" '
190+
'--resource-group "{rg}"',
191+
checks=checks)
192+
168193
def step_database_update(test, checks=None):
169194
if checks is None:
170195
checks = []

src/redisenterprise/azext_redisenterprise/tests/latest/recordings/test_redisenterprise_scenario7.yaml

Lines changed: 3528 additions & 0 deletions
Large diffs are not rendered by default.

src/redisenterprise/azext_redisenterprise/tests/latest/test_demo.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from .example_steps import step_database_delete
2121
from .example_steps import step_database_force_unlink
2222
from .example_steps import step_database_update
23+
from .example_steps import step_update
2324
from .example_steps import step_database_access_policy_assignment_create
2425
from .example_steps import step_database_access_policy_assignment_list
2526
from .example_steps import step_database_access_policy_assignment_delete
@@ -588,3 +589,96 @@ def test_redisenterprise_scenario6(self, rg):
588589
call_scenario6(self, rg)
589590
calc_coverage(__file__)
590591
raise_if()
592+
593+
594+
# Env setup_scenario7
595+
@try_manual
596+
def setup_scenario7(test):
597+
pass
598+
599+
600+
# Env cleanup_scenario7
601+
@try_manual
602+
def cleanup_scenario7(test):
603+
pass
604+
605+
606+
# Testcase: scenario7 - SKU Update Testing for RedisEnterpriseUpdate
607+
def call_scenario7(test, rg):
608+
"""Test scenario specifically for SKU update functionality with RedisEnterpriseUpdate class"""
609+
setup_scenario7(test)
610+
611+
# Create initial cluster
612+
step_create(test, checks=[
613+
test.check("name", "default"),
614+
test.check("resourceGroup", "{rg}"),
615+
test.check("clientProtocol", "Encrypted"),
616+
test.check("clusteringPolicy", "EnterpriseCluster"),
617+
test.check("evictionPolicy", "NoEviction"),
618+
test.check("port", 10000),
619+
test.check("provisioningState", "Succeeded"),
620+
test.check("resourceState", "Running"),
621+
test.check("type", "Microsoft.Cache/redisEnterprise/databases")
622+
])
623+
624+
# Verify initial cluster with Enterprise SKU has capacity and zones
625+
step_show(test, checks=[
626+
test.check("name", "{cluster}"),
627+
test.check("resourceGroup", "{rg}"),
628+
test.check("location", "Central US EUAP"),
629+
test.check("sku.name", "Balanced_B5"),
630+
test.check("sku.capacity", None),
631+
test.check("zones", None),
632+
test.check("provisioningState", "Succeeded"),
633+
test.check("resourceState", "Running"),
634+
test.check("type", "Microsoft.Cache/redisEnterprise"),
635+
test.check("databases[0].name", "default")
636+
])
637+
638+
step_update(test, checks=[
639+
test.check("name", "{cluster}"),
640+
test.check("resourceGroup", "{rg}"),
641+
test.check("sku.name", "ComputeOptimized_X5"),
642+
test.check("sku.capacity", None),
643+
test.check("zones", None),
644+
test.check("provisioningState", "Succeeded"),
645+
test.check("resourceState", "Running"),
646+
test.check("type", "Microsoft.Cache/redisEnterprise")
647+
])
648+
649+
# Verify the updated cluster state
650+
step_show(test, checks=[
651+
test.check("name", "{cluster}"),
652+
test.check("resourceGroup", "{rg}"),
653+
test.check("sku.name", "ComputeOptimized_X5"),
654+
test.check("sku.capacity", None),
655+
test.check("zones", None),
656+
test.check("provisioningState", "Succeeded"),
657+
test.check("resourceState", "Running"),
658+
test.check("type", "Microsoft.Cache/redisEnterprise")
659+
])
660+
661+
step_delete(test, checks=[])
662+
cleanup_scenario7(test)
663+
664+
665+
# Test class for scenario7 - SKU Update Testing
666+
class Redisenterprisescenario7Test(ScenarioTest):
667+
668+
def __init__(self, *args, **kwargs):
669+
super(Redisenterprisescenario7Test, self).__init__(*args, **kwargs)
670+
671+
self.kwargs.update({
672+
'cluster': self.create_random_name(prefix='clitest-cache7-', length=21),
673+
'sku-update': True,
674+
'initial_sku': 'Balanced_B5',
675+
'new_sku': 'ComputeOptimized_X5'
676+
})
677+
678+
@AllowLargeResponse(size_kb=9999)
679+
@ResourceGroupPreparer(name_prefix='clitest-redisenterprise-rg7-', key='rg', parameter_name='rg',
680+
location='centraluseuap', random_name_length=34)
681+
def test_redisenterprise_scenario7(self, rg):
682+
call_scenario7(self, rg)
683+
calc_coverage(__file__)
684+
raise_if()

src/redisenterprise/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111

1212
# HISTORY.rst entry.
13-
VERSION = '1.3.0'
13+
VERSION = '1.3.1'
1414

1515
# The full list of classifiers is available at
1616
# https://pypi.python.org/pypi?%3Aaction=list_classifiers

0 commit comments

Comments
 (0)