Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding CRUD azure cli commands for Managed instance and Managed database resources #6428

Merged
merged 11 commits into from
May 31, 2018
17 changes: 17 additions & 0 deletions src/command_modules/azure-cli-sql/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,23 @@
Release History
===============

2.0.27
++++++
* Added new Managed instance and Managed database CRUD commands.
* Managed instance commands:
* az sql mi create
* az sql mi show
* az sql mi list
* az sql mi update
* az sql mi delete

* Managed database commands:
* az sql midb create
* az sql midb show
* az sql midb list
* az sql midb restore
* az sql midb delete

2.0.26
++++++
* BREAKING CHANGES: Updated database, data warehouse, and elastic pool commands to use Azure-standard SKU properties for configuring performance level. This has resulted in some changes to the respose objects returned from db, dw, and elastic-pool commands.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -426,3 +426,85 @@
- name: Create a vnet rule by providing the vnet and subnet name. The subnet id is created by taking the resource group name and subscription id of the SQL server.
text: az sql server vnet-rule create --subnet subnetName --vnet-name vnetName
"""
helps['sql mi'] = """
type: group
short-summary: Manage SQL managed instances.
"""
helps['sql mi create'] = """
type: command
short-summary: Create a managed instance.
examples:
- name: Create a managed instance with specified parameters and with identity
text: az sql mi create -g mygroup -n myinstance -l mylocation -i -u myusername -p mypassword --license-type LicenseIncluded --subnet /subscriptions/{SubID}/resourceGroups/{ResourceGroup}/providers/Microsoft.Network/virtualNetworks/{VNETName}/subnets/{SubnetName} --capacity 8 --storage 32GB --edition GeneralPurpose --family Gen4
- name: Create a managed instance with minimal set of parameters
text: az sql mi create -g mygroup -n myinstance -l mylocation -i -u myusername -p mypassword --subnet /subscriptions/{SubID}/resourceGroups/{ResourceGroup}/providers/Microsoft.Network/virtualNetworks/{VNETName}/subnets/{SubnetName}
"""
helps['sql mi list'] = """
type: command
short-summary: List available managed instances.
examples:
- name: List all managed instances in the current subscription.
text: az sql mi list
- name: List all managed instances in a resource group.
text: az sql mi list -g mygroup
"""
helps['sql mi show'] = """
type: command
short-summary: Get the details for a managed instance.
examples:
- name: Get the details for a managed instance
text: az sql mi show -g mygroup -n myinstance
"""
helps['sql mi update'] = """
type: command
short-summary: Update a managed instance.
examples:
- name: Updates a mi with specified parameters and with identity
text: az sql mi update -g mygroup -n myinstance -i -p mypassword --license-type mylicensetype --capacity vcorecapacity --storage storagesize
"""
helps['sql mi delete'] = """
type: command
short-summary: Delete a managed instance.
examples:
- name: Delete a managed instance
text: az sql mi delete -g mygroup -n myinstance --yes
"""
helps['sql midb'] = """
type: group
short-summary: Manage SQL managed instance databases.
"""
helps['sql midb create'] = """
type: command
short-summary: Create a managed database.
examples:
- name: Create a managed database with specified collation
text: az sql midb create -g mygroup --mi myinstance -n mymanageddb --collation Latin1_General_100_CS_AS_SC
"""
helps['sql midb list'] = """
type: command
short-summary: List maanged databases on a managed instance.
examples:
- name: List managed databases on a managed instance
text: az sql midb list -g mygroup --mi myinstance
"""
helps['sql midb show'] = """
type: command
short-summary: Get the details for a managed database.
examples:
- name: Get the details for a managed database
text: az sql midb show -g mygroup --mi myinstance -n mymanageddb
"""
helps['sql midb restore'] = """
type: command
short-summary: Restore a managed database.
examples:
- name: Restore a managed database using Point in time restore
text: az sql midb restore -g mygroup --mi myinstance -n mymanageddb --dest-name targetmidb --time "2018-05-20T05:34:22"
"""
helps['sql midb delete'] = """
type: command
short-summary: Delete a managed database.
examples:
- name: Delete a managed database
text: az sql midb delete -g mygroup --mi myinstance -n mymanageddb --yes
"""
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
ElasticPoolPerDatabaseSettings,
ImportExtensionRequest,
ExportRequest,
ManagedDatabase,
ManagedInstance,
Server,
ServerAzureADAdministrator,
Sku
Expand Down Expand Up @@ -54,7 +56,9 @@

from ._validators import (
create_args_for_complex_type,
validate_elastic_pool_id
validate_elastic_pool_id,
validate_managed_instance_storage_size,
validate_subnet
)


Expand Down Expand Up @@ -82,7 +86,7 @@ def __call__(self, value):
try:
uvals = (self.unit_map[unit_part] if unit_part else 1) / \
(self.unit_map[self.unit] if self.unit else 1)
return self.result_type(uvals) * self.result_type(numeric_part)
return self.result_type(uvals * self.result_type(numeric_part))
except KeyError:
raise ValueError()

Expand Down Expand Up @@ -140,6 +144,19 @@ def __repr__(self):
help='Specifies whether to enable zone redundancy',
arg_type=get_three_state_flag())

managed_instance_param_type = CLIArgumentType(
options_list=['--managed-instance', '--mi'],
help='Name of the Azure SQL managed instance.')

storage_param_type = CLIArgumentType(
options_list=['--storage'],
type=SizeWithUnitConverter('GB', result_type=int, unit_map=dict(B=1.0 / (1024 * 1024 * 1024),
kB=1.0 / (1024 * 1024),
MB=1.0 / 1024,
GB=1,
TB=1024)),
Copy link
Contributor

Choose a reason for hiding this comment

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

result_type and unit_map don't need to be explicitly specified here, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually we have to, otherwise wrong dict will be used. In our case storage should be specified in GB and converted to it before sending the request

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, I didn't see that the multipliers are different. Cool!

help='The storage size. If no unit is specified, defaults to gigabytes (GB).',
validator=validate_managed_instance_storage_size)

db_service_objective_examples = 'Basic, S0, P1, GP_Gen4_1, BC_Gen5_2.'
dw_service_objective_examples = 'DW100, DW1000c'
Expand Down Expand Up @@ -1005,3 +1022,161 @@ def _configure_security_policy_storage_params(arg_ctx):
c.extra('vnet_name',
options_list=['--vnet-name'],
help='The virtual network name')

###############################################
# sql managed instance #
###############################################
with self.argument_context('sql mi') as c:
c.argument('managed_instance_name',
help='The managed instance name',
options_list=['--name', '-n'],
# Allow --ids command line argument. id_part=name is 1st name in uri
id_part='name')

c.argument('tier',
arg_type=tier_param_type,
help='The edition component of the sku. Allowed value is GeneralPurpose.')

c.argument('family',
arg_type=family_param_type,
help='The compute generation component of the sku. '
'Allowed values include: Gen4, Gen5.')

c.argument('storage_size_in_gb',
options_list=['--storage'],
arg_type=storage_param_type,
help='The storage size of the managed instance. '
'Storage size must be specified in increments of 32 GB')

c.argument('license_type',
arg_type=get_enum_type(DatabaseLicenseType),
help='The license type to apply for this managed instance.')

c.argument('vcores',
options_list=['--capacity', '-c'],
help='The capacity of the managed instance in vcores.')

with self.argument_context('sql mi create') as c:
# Create args that will be used to build up the ManagedInstance object
create_args_for_complex_type(
c, 'parameters', ManagedInstance, [
'administrator_login',
'administrator_login_password',
'license_type',
'virtual_network_subnet_id',
'vcores',
'storage_size_in_gb'
])

# Create args that will be used to build up the Managed Instance's Sku object
create_args_for_complex_type(
c, 'sku', Sku, [
'family',
'name',
'tier',
])

c.ignore('name') # Hide sku name

c.argument('administrator_login',
options_list=['--admin-user', '-u'],
required=True)

c.argument('administrator_login_password',
options_list=['--admin-password', '-p'],
required=True)

c.extra('vnet_name',
options_list=['--vnet-name'],
help='The virtual network name',
validator=validate_subnet)

c.argument('virtual_network_subnet_id',
options_list=['--subnet'],
required=True,
help='Name or ID of the subnet that allows access to an Azure Sql Managed Instance. '
'If subnet name is provided, --vnet-name must be provided.')

c.argument('assign_identity',
options_list=['--assign-identity', '-i'],
help='Generate and assign an Azure Active Directory Identity for this managed instance '
'for use with key management services like Azure KeyVault.')

with self.argument_context('sql mi update') as c:
# Create args that will be used to build up the ManagedInstance object
create_args_for_complex_type(
c, 'parameters', ManagedInstance, [
'administrator_login_password',
])

c.argument('administrator_login_password',
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of repeating c.argument('administrator_login_password', and c.argument('assign_identity',, you can just define them once in in with self.argument_context('sql managed-instance') as c:, section

Copy link
Contributor Author

@petrajkogit petrajkogit May 31, 2018

Choose a reason for hiding this comment

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

I am not actually repeating them. They are different in properties. administrator_login_password is required when creating instance, and optional when updating it. And assign_identity provides additional help info when doing update instance.

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

options_list=['--admin-password', '-p'])

c.argument('assign_identity',
options_list=['--assign-identity', '-i'],
help='Generate and assign an Azure Active Directory Identity for this managed instance '
'for use with key management services like Azure KeyVault. '
'If identity is already assigned - do nothing.')

###############################################
# sql managed db #
###############################################
with self.argument_context('sql midb') as c:
c.argument('managed_instance_name',
arg_type=managed_instance_param_type,
# Allow --ids command line argument. id_part=name is 1st name in uri
id_part='name')

c.argument('database_name',
options_list=['--name', '-n'],
help='The name of the Azure SQL Managed Database.',
# Allow --ids command line argument. id_part=child_name_1 is 2nd name in uri
id_part='child_name_1')

with self.argument_context('sql midb create') as c:
create_args_for_complex_type(
c, 'parameters', ManagedDatabase, [
'collation',
])

c.argument('collation',
required=False,
help='The collation of the Azure SQL Managed Database collation to use, '
'e.g.: SQL_Latin1_General_CP1_CI_AS or Latin1_General_100_CS_AS_SC')

with self.argument_context('sql midb restore') as c:
create_args_for_complex_type(
c, 'parameters', ManagedDatabase, [
'target_managed_database_name',
'target_managed_instance_name',
'restore_point_in_time'
])

c.argument('target_managed_database_name',
options_list=['--dest-name'],
required=True,
help='Name of the managed database that will be created as the restore destination.')

c.argument('target_managed_instance_name',
options_list=['--dest-mi'],
help='Name of the managed instance to restore managed database to. '
'This can be same managed instance, or another managed instance on same subscription. '
'When not specified it defaults to source managed instance.')

c.argument('target_resource_group_name',
options_list=['--dest-resource-group'],
help='Name of the resource group of the managed instance to restore managed database to. '
'When not specified it defaults to source resource group.')

restore_point_arg_group = 'Restore Point'

c.argument('restore_point_in_time',
options_list=['--time', '-t'],
arg_group=restore_point_arg_group,
required=True,
help='The point in time of the source database that will be restored to create the'
' new database. Must be greater than or equal to the source database\'s'
' earliestRestoreDate value. Time should be in following format: "YYYY-MM-DDTHH:MM:SS"')
Copy link
Contributor

Choose a reason for hiding this comment

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

Very nice!


with self.argument_context('sql midb list') as c:
c.argument('managed_instance_name', id_part=None)
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,11 @@ def get_sql_subscription_usages_operations(cli_ctx, _):

def get_sql_virtual_network_rules_operations(cli_ctx, _):
return get_sql_management_client(cli_ctx).virtual_network_rules


def get_sql_managed_instances_operations(cli_ctx, _):
return get_sql_management_client(cli_ctx).managed_instances


def get_sql_managed_databases_operations(cli_ctx, _):
return get_sql_management_client(cli_ctx).managed_databases
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,16 @@ def validate_subnet(cmd, namespace):
else:
raise CLIError('incorrect usage: [--subnet ID | --subnet NAME --vnet-name NAME]')
delattr(namespace, 'vnet_name')


###############################################
# sql managed instance #
###############################################


def validate_managed_instance_storage_size(namespace):
# Validate if entered storage size value is an increment of 32 if provided
if (not namespace.storage_size_in_gb) or (namespace.storage_size_in_gb and namespace.storage_size_in_gb % 32 == 0):
pass
else:
raise CLIError('incorrect usage: --storage must be specified in increments of 32 GB')
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
get_sql_elastic_pool_operations_operations,
get_sql_encryption_protectors_operations,
get_sql_firewall_rules_operations,
get_sql_managed_databases_operations,
get_sql_managed_instances_operations,
get_sql_replication_links_operations,
get_sql_restorable_dropped_databases_operations,
get_sql_server_connection_policies_operations,
Expand Down Expand Up @@ -406,3 +408,39 @@ def load_command_table(self, _):
c.command('create', 'create_or_update')
c.command('delete', 'delete')
c.custom_command('set', 'server_dns_alias_set')

###############################################
# sql managed instance #
###############################################

managed_instances_operations = CliCommandType(
operations_tmpl='azure.mgmt.sql.operations.managed_instances_operations#ManagedInstancesOperations.{}',
client_factory=get_sql_managed_instances_operations)

with self.command_group('sql mi',
managed_instances_operations,
client_factory=get_sql_managed_instances_operations) as g:

g.custom_command('create', 'managed_instance_create', supports_no_wait=True)
g.command('delete', 'delete', confirmation=True, supports_no_wait=True)
g.command('show', 'get')
g.custom_command('list', 'managed_instance_list')
g.generic_update_command('update', custom_func_name='managed_instance_update', supports_no_wait=True)

###############################################
# sql managed db #
###############################################

managed_databases_operations = CliCommandType(
operations_tmpl='azure.mgmt.sql.operations.managed_databases_operations#ManagedDatabasesOperations.{}',
client_factory=get_sql_managed_databases_operations)

with self.command_group('sql midb',
managed_databases_operations,
client_factory=get_sql_managed_databases_operations) as g:

g.custom_command('create', 'managed_db_create', supports_no_wait=True)
g.custom_command('restore', 'managed_db_restore', supports_no_wait=True)
g.command('show', 'get')
g.command('list', 'list_by_instance')
g.command('delete', 'delete', confirmation=True, supports_no_wait=True)
Loading