diff --git a/src/azure-cli/azure/cli/command_modules/rdbms/_flexible_server_util.py b/src/azure-cli/azure/cli/command_modules/rdbms/_flexible_server_util.py index 8ee9edf2cac..6840c0f7933 100644 --- a/src/azure-cli/azure/cli/command_modules/rdbms/_flexible_server_util.py +++ b/src/azure-cli/azure/cli/command_modules/rdbms/_flexible_server_util.py @@ -14,7 +14,8 @@ logger = get_logger(__name__) -DEFAULT_LOCATION = 'eastus' # For testing: 'eastus2euap' +DEFAULT_LOCATION_PG = 'eastus' # For testing: 'eastus2euap' +DEFAULT_LOCATION_MySQL = 'westus2' def resolve_poller(result, cli_ctx, name): @@ -29,10 +30,13 @@ def create_random_resource_name(prefix='azure', length=15): return prefix + ''.join(digits) -def generate_missing_parameters(cmd, location, resource_group_name, server_name): +def generate_missing_parameters(cmd, location, resource_group_name, server_name, db_engine): # if location is not passed as a parameter or is missing from local context if location is None: - location = DEFAULT_LOCATION + if db_engine == 'postgres': + location = DEFAULT_LOCATION_PG + else: + location = DEFAULT_LOCATION_MySQL # If resource group is there in local context, check for its existence. resource_group_exists = True @@ -60,14 +64,14 @@ def generate_missing_parameters(cmd, location, resource_group_name, server_name) def generate_password(administrator_login_password): import secrets + import string if administrator_login_password is None: - passwordLength = 16 - special_character = random.choice('!@#,?;:$&*') - administrator_login_password = secrets.token_urlsafe(passwordLength) - random_position = random.randint(1, len(administrator_login_password) - 1) - administrator_login_password = administrator_login_password[ - :random_position] + special_character + administrator_login_password[ - random_position + 1:] + passwordlength = 16 + administrator_login_password = secrets.token_urlsafe(passwordlength) + index = administrator_login_password.find("-") + if index != -1: + replaced_char = random.choice(string.ascii_letters) + administrator_login_password = administrator_login_password.replace("-", replaced_char) return administrator_login_password diff --git a/src/azure-cli/azure/cli/command_modules/rdbms/_params.py b/src/azure-cli/azure/cli/command_modules/rdbms/_params.py index 6affbd581d5..3898ff15b5c 100644 --- a/src/azure-cli/azure/cli/command_modules/rdbms/_params.py +++ b/src/azure-cli/azure/cli/command_modules/rdbms/_params.py @@ -16,7 +16,7 @@ get_three_state_flag) from azure.cli.command_modules.rdbms.validators import configuration_value_validator, validate_subnet, \ retention_validator, tls_validator, public_access_validator, pg_storage_validator, mysql_storage_validator, tier_validator, \ - pg_sku_name_validator, mysql_sku_name_validator, pg_version_validator, mysql_version_validator, maintenance_window_validator, ip_address_validator + pg_sku_name_validator, pg_version_validator, mysql_version_validator, maintenance_window_validator, ip_address_validator from azure.cli.core.commands.validators import get_default_location_from_resource_group from azure.cli.core.local_context import LocalContextAttribute, LocalContextAction @@ -240,9 +240,9 @@ def _flexible_server_params(command_group): c.argument('zone', options_list=['--zone, -z'], help='Availability zone into which to provision the resource.') elif command_group == 'mysql': - c.argument('tier', default='Burstable', validator=tier_validator, + c.argument('tier', default='Burstable', help='Compute tier of the server. Accepted values: Burstable, GeneralPurpose, Memory Optimized ') - c.argument('sku_name', default='Standard_B1ms', options_list=['--sku-name'], validator=mysql_sku_name_validator, + c.argument('sku_name', default='Standard_B1ms', options_list=['--sku-name'], help='The name of the compute SKU. Follows the convention Standard_{VM name}. Examples: Standard_B1ms, Standard_D4s_v3 ') c.argument('storage_mb', default='10', options_list=['--storage-size'], type=int, validator=mysql_storage_validator, help='The storage capacity of the server. Minimum is 5 GiB and increases in 1 GiB increments. Max is 16 TiB.') @@ -290,8 +290,6 @@ def _flexible_server_params(command_group): with self.argument_context('{} flexible-server update'.format(command_group)) as c: c.ignore('assign_identity') - c.argument('tier', options_list=['--tier'], validator=tier_validator, - help='Compute tier of the server. Accepted values: Burstable, GeneralPurpose, Memory Optimized ') c.argument('backup_retention', type=int, options_list=['--backup-retention'], help='The number of days a backup is retained. Range of 7 to 35 days. Default is 7 days.', validator=retention_validator) c.argument('administrator_login_password', options_list=['--admin-password', '-p'], @@ -302,7 +300,9 @@ def _flexible_server_params(command_group): help='Period of time (UTC) designated for maintenance. Examples: "Sun:23:30" to schedule on Sunday, 11:30pm UTC. To set back to default pass in "Disabled".') c.argument('tags', tags_type) if command_group == 'mysql': - c.argument('sku_name', options_list=['--sku-name'], validator=mysql_sku_name_validator, + c.argument('tier', options_list=['--tier'], + help='Compute tier of the server. Accepted values: Burstable, GeneralPurpose, Memory Optimized ') + c.argument('sku_name', options_list=['--sku-name'], help='The name of the compute SKU. Follows the convention Standard_{VM name}. Examples: Standard_B1ms, Standard_D4s_v3 ') c.argument('storage_mb', options_list=['--storage-size'], type=int, validator=mysql_storage_validator, @@ -317,6 +317,8 @@ def _flexible_server_params(command_group): c.argument('replication_role', options_list=['--replication-role'], help='The replication role of the server.') elif command_group == 'postgres': + c.argument('tier', options_list=['--tier'], validator=tier_validator, + help='Compute tier of the server. Accepted values: Burstable, GeneralPurpose, Memory Optimized ') c.argument('sku_name', options_list=['--sku-name'], validator=pg_sku_name_validator, help='The name of the compute SKU. Follows the convention Standard_{VM name}. Examples: Standard_D4s_v3 ') c.argument('storage_mb', options_list=['--storage-size'], type=int, @@ -410,13 +412,15 @@ def _flexible_server_params(command_group): with self.argument_context('{} flexible-server replica create'.format(command_group)) as c: c.argument('source_server', options_list=['--source-server'], help='The name or resource ID of the source server to restore from.') - c.argument('tier', options_list=['--tier'], validator=tier_validator, - help='Compute tier of the server. Accepted values: Burstable, GeneralPurpose, Memory Optimized ') if command_group == 'mysql': + c.argument('tier', options_list=['--tier'], + help='Compute tier of the server. Accepted values: Burstable, GeneralPurpose, Memory Optimized ') c.argument('sku_name', options_list=['--sku-name'], - validator=mysql_sku_name_validator, help='The name of the compute SKU. Follows the convention' ' Standard_{VM name}. Examples: Standard_B1ms, Standard_D4s_v3 ') + if command_group == 'postgres': + c.argument('tier', options_list=['--tier'], validator=tier_validator, + help='Compute tier of the server. Accepted values: Burstable, GeneralPurpose, Memory Optimized ') with self.argument_context('{} flexible-server replica stop-replication'.format(command_group)) as c: c.argument('server_name', options_list=['--name', '-s'], help='Name of the server.') diff --git a/src/azure-cli/azure/cli/command_modules/rdbms/flexible_server_custom_mysql.py b/src/azure-cli/azure/cli/command_modules/rdbms/flexible_server_custom_mysql.py index 77f3c565e5c..de671b4e96a 100644 --- a/src/azure-cli/azure/cli/command_modules/rdbms/flexible_server_custom_mysql.py +++ b/src/azure-cli/azure/cli/command_modules/rdbms/flexible_server_custom_mysql.py @@ -56,7 +56,8 @@ def flexible_server_create(cmd, client, resource_group_name=None, server_name=No # Populate desired parameters location, resource_group_name, server_name = generate_missing_parameters(cmd, location, resource_group_name, - server_name) + server_name, 'mysql') + server_name = server_name.lower() # Handle Vnet scenario if (subnet_arm_resource_id is not None) or (vnet_resource_id is not None): @@ -116,8 +117,8 @@ def flexible_server_create(cmd, client, resource_group_name=None, server_name=No sku = server_result.sku.name host = server_result.fully_qualified_domain_name - logger.warning('Make a note of your password. If you forget, you would have to reset your password with \ - \'az mysql flexible-server update -n %s -g %s -p \'.', + logger.warning('Make a note of your password. If you forget, you would have to ' + 'reset your password with \'az mysql flexible-server update -n %s -g %s -p \'.', server_name, resource_group_name) _update_local_contexts(cmd, server_name, resource_group_name, location, user) diff --git a/src/azure-cli/azure/cli/command_modules/rdbms/flexible_server_custom_postgres.py b/src/azure-cli/azure/cli/command_modules/rdbms/flexible_server_custom_postgres.py index 4b15e115b7a..05c80b04c38 100644 --- a/src/azure-cli/azure/cli/command_modules/rdbms/flexible_server_custom_postgres.py +++ b/src/azure-cli/azure/cli/command_modules/rdbms/flexible_server_custom_postgres.py @@ -59,7 +59,8 @@ def flexible_server_create(cmd, client, # Populate desired parameters location, resource_group_name, server_name = generate_missing_parameters(cmd, location, resource_group_name, - server_name) + server_name, 'postgres') + server_name = server_name.lower() # Handle Vnet scenario if (subnet_arm_resource_id is not None) or (vnet_resource_id is not None): @@ -113,15 +114,15 @@ def flexible_server_create(cmd, client, sku = server_result.sku.name host = server_result.fully_qualified_domain_name - logger.warning('Make a note of your password. If you forget, you would have to \ - reset your password with \'az postgres flexible-server update -n %s -g %s -p \'.', + logger.warning('Make a note of your password. If you forget, you would have to ' + 'reset your password with \'az postgres flexible-server update -n %s -g %s -p \'.', server_name, resource_group_name) _update_local_contexts(cmd, server_name, resource_group_name, location, user) return _form_response(user, sku, loc, server_id, host, version, administrator_login_password if administrator_login_password is not None else '*****', - _create_postgresql_connection_string(host, administrator_login_password), firewall_id, + _create_postgresql_connection_string(host, user, administrator_login_password), firewall_id, subnet_id) except Exception as ex: # pylint: disable=broad-except logger.error(ex) @@ -329,7 +330,7 @@ def flexible_server_connection_string( def _create_postgresql_connection_strings(host, user, password, database): result = { - 'psql_cmd': "psql --host={host} --port=5432 --username={user} --dbname=postgres", + 'psql_cmd': "postgresql://{user}:{password}@{host}/postgres?sslmode=require", 'ado.net': "Server={host};Database=postgres;Port=5432;User Id={user};Password={password};", 'jdbc': "jdbc:postgresql://{host}:5432/postgres?user={user}&password={password}", 'jdbc Spring': "spring.datasource.url=jdbc:postgresql://{host}:5432/postgres " @@ -355,12 +356,13 @@ def _create_postgresql_connection_strings(host, user, password, database): return result -def _create_postgresql_connection_string(host, password): +def _create_postgresql_connection_string(host, user, password): connection_kwargs = { + 'user': user, 'host': host, 'password': password if password is not None else '{password}' } - return 'postgres://postgres:{password}@{host}/postgres?sslmode=require'.format(**connection_kwargs) + return 'postgresql://{user}:{password}@{host}/postgres?sslmode=require'.format(**connection_kwargs) def _form_response(username, sku, location, server_id, host, version, password, connection_string, firewall_id=None, diff --git a/src/azure-cli/azure/cli/command_modules/rdbms/flexible_server_virtual_network.py b/src/azure-cli/azure/cli/command_modules/rdbms/flexible_server_virtual_network.py index 996749ff9fa..aed77792d9b 100644 --- a/src/azure-cli/azure/cli/command_modules/rdbms/flexible_server_virtual_network.py +++ b/src/azure-cli/azure/cli/command_modules/rdbms/flexible_server_virtual_network.py @@ -59,7 +59,7 @@ def prepare_vnet(cmd, server_name, vnet, subnet, resource_group_name, loc, deleg "The Subnet does not exist with the supplied subnet id. Checking the existence of the Vnet in the supplied Id...") subnet_result = _create_vnet_subnet_delegation(nw_client, resource_group, vnet_name, - server_name + 'Subnet', location, server_name, + 'Subnet' + server_name[6:], location, server_name, delegation, VirtualNetwork, Subnet, AddressSpace, DEFAULT_VNET_ADDRESS_PREFIX, DEFAULT_SUBNET_PREFIX) @@ -77,13 +77,13 @@ def prepare_vnet(cmd, server_name, vnet, subnet, resource_group_name, loc, deleg location = rg.location validate_rg_loc_sub(resource_group, subscription, location, resource_group_name, get_subscription_id(cmd.cli_ctx), loc) - subnet_result = _create_vnet_subnet_delegation(nw_client, resource_group, vnet_name, server_name + 'Subnet', + subnet_result = _create_vnet_subnet_delegation(nw_client, resource_group, vnet_name, 'Subnet' + server_name[6:], location, server_name, delegation, VirtualNetwork, Subnet, AddressSpace, DEFAULT_VNET_ADDRESS_PREFIX, DEFAULT_SUBNET_PREFIX) elif len(vnet.split('\\')) == 1: logger.warning("You have supplied a Vnet Name. Verifying its existence...") - subnet_result = _create_vnet_subnet_delegation(nw_client, resource_group_name, vnet, server_name + 'Subnet', + subnet_result = _create_vnet_subnet_delegation(nw_client, resource_group_name, vnet, 'Subnet' + server_name[6:], loc, server_name, delegation, VirtualNetwork, Subnet, AddressSpace, DEFAULT_VNET_ADDRESS_PREFIX, DEFAULT_SUBNET_PREFIX) @@ -210,7 +210,7 @@ def create_vnet(cmd, servername, location, resource_group_name, delegation_servi 'Delegation', resource_type=ResourceType.MGMT_NETWORK) client = network_client_factory(cmd.cli_ctx) - vnet_name, subnet_name, vnet_address_prefix, subnet_prefix = _create_vnet_metadata(servername) + vnet_name, subnet_name, vnet_address_prefix, subnet_prefix = _create_vnet_metadata(servername[6:]) logger.warning('Creating new vnet "%s" in resource group "%s"...', vnet_name, resource_group_name) client.virtual_networks.create_or_update(resource_group_name, vnet_name, @@ -227,8 +227,8 @@ def create_vnet(cmd, servername, location, resource_group_name, delegation_servi def _create_vnet_metadata(servername): - vnet_name = servername + 'VNET' - subnet_name = servername + 'Subnet' + vnet_name = 'VNET' + servername + subnet_name = 'Subnet' + servername vnet_address_prefix = DEFAULT_VNET_ADDRESS_PREFIX subnet_prefix = DEFAULT_SUBNET_PREFIX return vnet_name, subnet_name, vnet_address_prefix, subnet_prefix diff --git a/src/azure-cli/azure/cli/command_modules/rdbms/validators.py b/src/azure-cli/azure/cli/command_modules/rdbms/validators.py index 2b9a395ec63..fc7be1269ef 100644 --- a/src/azure-cli/azure/cli/command_modules/rdbms/validators.py +++ b/src/azure-cli/azure/cli/command_modules/rdbms/validators.py @@ -174,11 +174,11 @@ def mysql_sku_name_validator(ns): 'Examples: Standard_D4s_v3 Standard_E8s_v3 Standard_B1ms') elif len(ns.sku_name.split('_')) == 3: server_type, cpu, server_v3 = ns.sku_name.split('_') - if server_type != 'Standard' or server_v3 != 'v3': + if server_type != 'Standard' or server_v3 != 'v4': raise CLIError('Incorrect value for --sku-name. Follow the convention Standard_{VM name}. ' 'Examples: Standard_D4s_v3 Standard_B1ms') - if not re.match(r"^(D|E)\d+s$", cpu) or \ - (re.match(r"^(D|E)\d+s$", cpu) and int(cpu[1:-1]) not in [2, 4, 8, 16, 32, 48, 64]): + if not re.match(r"^(D|E)\d+ds$", cpu) or \ + (re.match(r"^(D|E)\d+ds$", cpu) and int(cpu[1:-1]) not in [2, 4, 8, 16, 32, 48, 64]): raise CLIError('Incorrect value for --sku-name. Follow the convention Standard_{VM name}. ' 'Examples: Standard_D4s_v3 Standard_E8s_v3 Standard_B1ms. ' '\nAllowed number of vCores: 2, 4, 8, 16, 32, 48, 64')