Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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':
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

db_engine.lower()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something that we are explicitly passing as lower case from the caller. Line 61 in flexible_server_custom_postgres.py.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you pls add some test to change the overall change?

Copy link
Contributor Author

@arde0708 arde0708 Sep 25, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this, we are just changing the default location from eastus to westus2 for MySQL. We already have tests for both MySQL and Postgres SQL creation otherwise.

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
Expand Down Expand Up @@ -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


Expand Down
22 changes: 13 additions & 9 deletions src/azure-cli/azure/cli/command_modules/rdbms/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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 ')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to get allowed sku values through SDK?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a permanent fix for this in S176 where we fetch the SKU's from the SDK. We are currently removing the validators in the PR as there is a bug in the validator which prevents provisioning servers with certain SKU's

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good

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.')
Expand Down Expand Up @@ -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'],
Expand All @@ -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 ')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For allowed values. prefer using get_enume_type()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in the SDK comment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean all allowed values for tier and sku_name. Could we also get the allowed array from sdk?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes we do have validators for tier, sku_name, storage size validated by the array from sdk. We will include that for the next train.

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,
Expand All @@ -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,
Expand Down Expand Up @@ -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.')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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 <new-password>\'.',
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 <new-password>\'.',
server_name, resource_group_name)

_update_local_contexts(cmd, server_name, resource_group_name, location, user)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please avoid positional arguments here

server_name = server_name.lower()

# Handle Vnet scenario
if (subnet_arm_resource_id is not None) or (vnet_resource_id is not None):
Expand Down Expand Up @@ -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 <new-password>\'.',
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 <new-password>\'.',
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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

avoid positional arguments here

subnet_id)
except Exception as ex: # pylint: disable=broad-except
logger.error(ex)
Expand Down Expand Up @@ -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 "
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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,
Expand All @@ -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
6 changes: 3 additions & 3 deletions src/azure-cli/azure/cli/command_modules/rdbms/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down