Skip to content

Commit 0d770d9

Browse files
authored
[Mysql] az mysql flexible-server create/restore/replica create/geo restore: Add --storage-redundancy parameter to support HA storage with zone redundancy (#30423)
* complete code * fix lint * code complete * fix linter problems * fix test * fix test * Update custom.py * update test files
1 parent bf7352f commit 0d770d9

File tree

39 files changed

+49637
-47797
lines changed

39 files changed

+49637
-47797
lines changed

src/azure-cli/azure/cli/command_modules/mysql/_client_factory.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,12 @@ def cf_mysql_flexible_log(cli_ctx, _):
9090
return get_mysql_flexible_management_client(cli_ctx).log_files
9191

9292

93+
def cf_mysql_flexible_backup(cli_ctx, _):
94+
return get_mysql_flexible_management_client(cli_ctx).long_running_backup
95+
96+
9397
def cf_mysql_flexible_backups(cli_ctx, _):
94-
return get_mysql_flexible_management_client(cli_ctx).backups
98+
return get_mysql_flexible_management_client(cli_ctx).long_running_backups
9599

96100

97101
def cf_mysql_flexible_export(cli_ctx, _):

src/azure-cli/azure/cli/command_modules/mysql/_params.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,12 @@ def load_arguments(self, _): # pylint: disable=too-many-statements, too-many-
122122
help='Enable or disable accelerated logs. Only support for Business Critical tier. Default value is Enabled.'
123123
)
124124

125+
storage_redundancy_arg_type = CLIArgumentType(
126+
arg_type=get_enum_type(['LocalRedundancy', 'ZoneRedundancy']),
127+
options_list=['--storage-redundancy'],
128+
help='Enable local redundancy or zone redundancy. Zone redundancy only supports Business Critical tier.'
129+
)
130+
125131
maintenance_policy_patch_strategy_arg_type = CLIArgumentType(
126132
arg_type=get_enum_type(['Regular', 'VirtualCanary']),
127133
options_list=['--maintenance-policy-patch-strategy', '--patch-strategy'],
@@ -347,6 +353,7 @@ def load_arguments(self, _): # pylint: disable=too-many-statements, too-many-
347353
c.argument('public_access', arg_type=public_access_create_arg_type)
348354
c.argument('vnet', arg_type=vnet_arg_type)
349355
c.argument('vnet_address_prefix', arg_type=vnet_address_prefix_arg_type)
356+
c.argument('storage_redundancy', arg_type=storage_redundancy_arg_type)
350357
c.argument('subnet', arg_type=subnet_arg_type)
351358
c.argument('subnet_address_prefix', arg_type=subnet_address_prefix_arg_type)
352359
c.argument('private_dns_zone_arguments', private_dns_zone_arguments_arg_type)
@@ -405,6 +412,7 @@ def load_arguments(self, _): # pylint: disable=too-many-statements, too-many-
405412
c.argument('vnet_address_prefix', arg_type=vnet_address_prefix_arg_type)
406413
c.argument('subnet', arg_type=subnet_arg_type)
407414
c.argument('subnet_address_prefix', arg_type=subnet_address_prefix_arg_type)
415+
c.argument('storage_redundancy', arg_type=storage_redundancy_arg_type)
408416
c.argument('private_dns_zone_arguments', private_dns_zone_arguments_arg_type)
409417
c.argument('zone', arg_type=zone_arg_type)
410418
c.argument('tags', tags_type)
@@ -436,6 +444,7 @@ def load_arguments(self, _): # pylint: disable=too-many-statements, too-many-
436444
c.argument('storage_gb', arg_type=storage_gb_arg_type)
437445
c.argument('auto_grow', arg_type=auto_grow_arg_type)
438446
c.argument('accelerated_logs', arg_type=accelerated_logs_arg_type)
447+
c.argument('storage_redundancy', arg_type=storage_redundancy_arg_type)
439448
c.argument('backup_retention', arg_type=mysql_backup_retention_arg_type)
440449
c.argument('geo_redundant_backup', arg_type=geo_redundant_backup_arg_type)
441450
c.argument('public_access', options_list=['--public-access'], arg_type=get_enum_type(['Enabled', 'Disabled']), help='Determines the public access. ')
@@ -564,6 +573,7 @@ def load_arguments(self, _): # pylint: disable=too-many-statements, too-many-
564573
c.argument('sku_name', arg_type=sku_name_arg_type)
565574
c.argument('storage_gb', arg_type=storage_gb_arg_type)
566575
c.argument('iops', arg_type=iops_arg_type)
576+
c.argument('storage_redundancy', arg_type=storage_redundancy_arg_type)
567577
c.argument('database_port', arg_type=database_port_arg_type)
568578
c.argument('backup_retention', arg_type=mysql_backup_retention_arg_type)
569579
c.argument('geo_redundant_backup', arg_type=geo_redundant_backup_arg_type)

src/azure-cli/azure/cli/command_modules/mysql/_validators.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def mysql_arguments_validator(db_context, location, tier, sku_name, storage_gb,
107107
public_access=None, version=None, auto_grow=None, replication_role=None, subnet=None,
108108
byok_identity=None, backup_byok_identity=None, byok_key=None, geo_redundant_backup=None,
109109
disable_data_encryption=None, iops=None, auto_io_scaling=None, accelerated_logs=None,
110-
instance=None, data_source_type=None, mode=None,
110+
storage_redundancy=None, instance=None, data_source_type=None, mode=None,
111111
data_source_backup_dir=None, data_source_sas_token=None):
112112
validate_server_name(db_context, server_name, 'Microsoft.DBforMySQL/flexibleServers')
113113

@@ -134,6 +134,7 @@ def mysql_arguments_validator(db_context, location, tier, sku_name, storage_gb,
134134
disable_data_encryption, geo_redundant_backup, instance)
135135
_mysql_iops_validator(iops, auto_io_scaling, instance)
136136
mysql_accelerated_logs_validator(accelerated_logs, tier)
137+
storage_redundancy_validator(storage_redundancy, tier)
137138
_mysql_import_data_source_type_validator(data_source_type, data_source_backup_dir, data_source_sas_token)
138139
_mysql_import_mode_validator(mode)
139140

@@ -316,6 +317,12 @@ def mysql_accelerated_logs_validator(accelerated_logs, tier):
316317
"So the accelerated logs will be disabled.")
317318

318319

320+
def storage_redundancy_validator(storage_redundancy, tier):
321+
if tier != "MemoryOptimized" and storage_redundancy is not None and storage_redundancy.lower() == "zoneredundancy":
322+
logger.warning("Zone Redundancy is only supported for Memory Optimized tier. "
323+
"So Local Redundancy will be enabled for your server.")
324+
325+
319326
def _network_arg_validator(subnet, public_access):
320327
if subnet is not None and public_access is not None:
321328
raise CLIError("Incorrect usage : A combination of the parameters --subnet "

src/azure-cli/azure/cli/command_modules/mysql/commands.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
cf_mysql_flexible_replica,
1414
cf_mysql_flexible_location_capabilities,
1515
cf_mysql_flexible_log,
16+
cf_mysql_flexible_backup,
1617
cf_mysql_flexible_backups,
1718
cf_mysql_flexible_adadmin,
1819
cf_mysql_flexible_export,
@@ -69,8 +70,13 @@ def load_command_table(self, _):
6970
client_factory=cf_mysql_flexible_log
7071
)
7172

72-
mysql_flexible_backups_sdk = CliCommandType(
73-
operations_tmpl='azure.mgmt.mysqlflexibleservers.operations#BackupsOperations.{}',
73+
mysql_flexible_long_running_backup_sdk = CliCommandType(
74+
operations_tmpl='azure.mgmt.mysqlflexibleservers.operations#LongRunningBackupOperations.{}',
75+
client_factory=cf_mysql_flexible_backup
76+
)
77+
78+
mysql_flexible_long_running_backups_sdk = CliCommandType(
79+
operations_tmpl='azure.mgmt.mysqlflexibleservers.operations#LongRunningBackupsOperations.{}',
7480
client_factory=cf_mysql_flexible_backups
7581
)
7682

@@ -185,10 +191,13 @@ def load_command_table(self, _):
185191
g.custom_command('list', 'flexible_server_log_list')
186192
g.custom_command('download', 'flexible_server_log_download')
187193

188-
with self.command_group('mysql flexible-server backup', mysql_flexible_backups_sdk,
194+
with self.command_group('mysql flexible-server backup', mysql_flexible_long_running_backup_sdk,
195+
client_factory=cf_mysql_flexible_backup) as g:
196+
g.command('create', 'begin_create')
197+
198+
with self.command_group('mysql flexible-server backup', mysql_flexible_long_running_backups_sdk,
189199
client_factory=cf_mysql_flexible_backups) as g:
190-
g.command('create', 'put', transform=transform_backup)
191-
g.command('list', 'list_by_server', transform=transform_backups_list)
200+
g.command('list', 'list', transform=transform_backups_list)
192201
g.show_command('show', 'get', transform=transform_backup)
193202

194203
with self.command_group('mysql flexible-server export', mysql_flexible_export_sdk,

src/azure-cli/azure/cli/command_modules/mysql/custom.py

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
from ._validators import mysql_arguments_validator, mysql_auto_grow_validator, mysql_georedundant_backup_validator, mysql_restore_tier_validator, mysql_accelerated_logs_validator, \
3333
mysql_retention_validator, mysql_sku_name_validator, mysql_storage_validator, validate_mysql_replica, validate_server_name, \
3434
validate_mysql_tier_update, validate_and_format_restore_point_in_time, validate_public_access_server, mysql_import_single_server_ready_validator, \
35-
mysql_import_version_validator, mysql_import_storage_validator, validate_and_format_maintenance_start_time
35+
mysql_import_version_validator, mysql_import_storage_validator, validate_and_format_maintenance_start_time, storage_redundancy_validator
3636

3737
logger = get_logger(__name__)
3838
DELEGATION_SERVICE_NAME = "Microsoft.DBforMySQL/flexibleServers"
@@ -337,8 +337,8 @@ def flexible_server_create(cmd, client,
337337
subnet=None, subnet_address_prefix=None, vnet=None, vnet_address_prefix=None,
338338
private_dns_zone_arguments=None, public_access=None,
339339
high_availability=None, zone=None, standby_availability_zone=None,
340-
iops=None, auto_grow=None, auto_scale_iops=None, accelerated_logs=None, geo_redundant_backup=None,
341-
byok_identity=None, backup_byok_identity=None, byok_key=None, backup_byok_key=None,
340+
iops=None, auto_grow=None, auto_scale_iops=None, accelerated_logs=None, storage_redundancy=None,
341+
geo_redundant_backup=None, byok_identity=None, backup_byok_identity=None, byok_key=None, backup_byok_key=None,
342342
maintenance_policy_patch_strategy=None, yes=False):
343343
# Generate missing parameters
344344
location, resource_group_name, server_name = generate_missing_parameters(cmd, location, resource_group_name, server_name)
@@ -376,6 +376,7 @@ def flexible_server_create(cmd, client,
376376
backup_byok_key=backup_byok_key,
377377
auto_io_scaling=auto_scale_iops,
378378
accelerated_logs=accelerated_logs,
379+
storage_redundancy=storage_redundancy,
379380
iops=iops)
380381
list_skus_info = get_mysql_list_skus_info(db_context.cmd, location)
381382
iops_info = list_skus_info['iops_info']
@@ -404,11 +405,14 @@ def flexible_server_create(cmd, client,
404405

405406
accelerated_logs = _determine_acceleratedLogs(accelerated_logs, tier)
406407

408+
storage_redundancy = _determine_storage_redundancy(storage_redundancy, tier)
409+
407410
storage = models.Storage(storage_size_gb=storage_gb,
408411
iops=iops,
409412
auto_grow=auto_grow,
410413
auto_io_scaling=auto_scale_iops,
411-
log_on_disk=accelerated_logs)
414+
log_on_disk=accelerated_logs,
415+
storage_redundancy=storage_redundancy)
412416

413417
backup = models.Backup(backup_retention_days=backup_retention, geo_redundant_backup=geo_redundant_backup)
414418

@@ -703,7 +707,8 @@ def flexible_server_import_replica_stop(client, resource_group_name, server_name
703707
def flexible_server_restore(cmd, client, resource_group_name, server_name, source_server, restore_point_in_time=None, zone=None,
704708
no_wait=False, subnet=None, subnet_address_prefix=None, vnet=None, vnet_address_prefix=None,
705709
private_dns_zone_arguments=None, public_access=None, yes=False, sku_name=None, tier=None, database_port=None,
706-
storage_gb=None, auto_grow=None, accelerated_logs=None, backup_retention=None, geo_redundant_backup=None, tags=None):
710+
storage_gb=None, auto_grow=None, accelerated_logs=None, storage_redundancy=None, backup_retention=None,
711+
geo_redundant_backup=None, tags=None):
707712
provider = 'Microsoft.DBforMySQL'
708713
server_name = server_name.lower()
709714

@@ -756,6 +761,11 @@ def flexible_server_restore(cmd, client, resource_group_name, server_name, sourc
756761
else:
757762
mysql_accelerated_logs_validator(accelerated_logs, tier)
758763

764+
if not storage_redundancy:
765+
storage_redundancy = source_server_object.storage.storage_redundancy
766+
else:
767+
storage_redundancy_validator(storage_redundancy, tier)
768+
759769
if not backup_retention:
760770
backup_retention = source_server_object.backup.backup_retention_days
761771
else:
@@ -779,7 +789,7 @@ def flexible_server_restore(cmd, client, resource_group_name, server_name, sourc
779789

780790
storage = models.Storage(storage_size_gb=storage_gb, iops=iops, auto_grow=auto_grow,
781791
auto_io_scaling=source_server_object.storage.auto_io_scaling,
782-
log_on_disk=accelerated_logs)
792+
log_on_disk=accelerated_logs, storage_redundancy=storage_redundancy)
783793

784794
backup = models.Backup(backup_retention_days=backup_retention, geo_redundant_backup=geo_redundant_backup)
785795

@@ -842,7 +852,8 @@ def flexible_server_restore(cmd, client, resource_group_name, server_name, sourc
842852
def flexible_server_georestore(cmd, client, resource_group_name, server_name, source_server, location, zone=None, no_wait=False,
843853
subnet=None, subnet_address_prefix=None, vnet=None, vnet_address_prefix=None, tags=None,
844854
private_dns_zone_arguments=None, public_access=None, yes=False, sku_name=None, tier=None,
845-
storage_gb=None, auto_grow=None, accelerated_logs=None, backup_retention=None, geo_redundant_backup=None):
855+
storage_gb=None, auto_grow=None, accelerated_logs=None, storage_redundancy=None,
856+
backup_retention=None, geo_redundant_backup=None):
846857
provider = 'Microsoft.DBforMySQL'
847858
server_name = server_name.lower()
848859

@@ -889,6 +900,11 @@ def flexible_server_georestore(cmd, client, resource_group_name, server_name, so
889900
else:
890901
mysql_accelerated_logs_validator(accelerated_logs, tier)
891902

903+
if not storage_redundancy:
904+
storage_redundancy = source_server_object.storage.storage_redundancy
905+
else:
906+
storage_redundancy_validator(storage_redundancy, tier)
907+
892908
if not backup_retention:
893909
backup_retention = source_server_object.backup.backup_retention_days
894910
else:
@@ -915,7 +931,7 @@ def flexible_server_georestore(cmd, client, resource_group_name, server_name, so
915931

916932
storage = models.Storage(storage_size_gb=storage_gb, iops=iops, auto_grow=auto_grow,
917933
auto_io_scaling=source_server_object.storage.auto_io_scaling,
918-
log_on_disk=accelerated_logs)
934+
log_on_disk=accelerated_logs, storage_redundancy=storage_redundancy)
919935

920936
backup = models.Backup(backup_retention_days=backup_retention, geo_redundant_backup=geo_redundant_backup)
921937

@@ -1311,7 +1327,8 @@ def flexible_parameter_update_batch(client, server_name, resource_group_name, so
13111327
# Custom functions for server replica, will add MySQL part after backend ready in future
13121328
def flexible_replica_create(cmd, client, resource_group_name, source_server, replica_name, location=None, tags=None, sku_name=None,
13131329
private_dns_zone_arguments=None, vnet=None, subnet=None, zone=None, public_access=None, no_wait=False,
1314-
storage_gb=None, iops=None, geo_redundant_backup=None, backup_retention=None, tier=None, database_port=None):
1330+
storage_gb=None, iops=None, storage_redundancy=None, geo_redundant_backup=None, backup_retention=None,
1331+
tier=None, database_port=None):
13151332
provider = 'Microsoft.DBforMySQL'
13161333
replica_name = replica_name.lower()
13171334

@@ -1356,12 +1373,18 @@ def flexible_replica_create(cmd, client, resource_group_name, source_server, rep
13561373
if not iops:
13571374
iops = source_server_object.storage.iops
13581375

1376+
if not storage_redundancy:
1377+
storage_redundancy = source_server_object.storage.storage_redundancy
1378+
else:
1379+
storage_redundancy_validator(storage_redundancy, tier)
1380+
13591381
identity, data_encryption = get_identity_and_data_encryption(source_server_object)
13601382

13611383
storage = models.Storage(storage_size_gb=storage_gb,
13621384
iops=iops,
13631385
auto_grow="Enabled",
1364-
auto_io_scaling=source_server_object.storage.auto_io_scaling)
1386+
auto_io_scaling=source_server_object.storage.auto_io_scaling,
1387+
storage_redundancy=storage_redundancy)
13651388

13661389
backup = models.Backup(backup_retention_days=backup_retention, geo_redundant_backup=geo_redundant_backup)
13671390

@@ -1649,6 +1672,15 @@ def _determine_acceleratedLogs(accelerated_logs, tier):
16491672
return accelerated_logs
16501673

16511674

1675+
def _determine_storage_redundancy(storage_redundancy, tier):
1676+
if storage_redundancy is None:
1677+
if tier == "MemoryOptimized":
1678+
storage_redundancy = "ZoneRedundancy"
1679+
else:
1680+
storage_redundancy = "LocalRedundancy"
1681+
return storage_redundancy
1682+
1683+
16521684
def get_free_iops(storage_in_mb, iops_info, tier, sku_name):
16531685
free_iops = MINIMUM_IOPS + (storage_in_mb // 1024) * 3
16541686
max_supported_iops = iops_info[tier][sku_name] # free iops cannot exceed maximum supported iops for the sku

0 commit comments

Comments
 (0)