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

[SQL VM] az sql vm update: Add configuration options for SQL Best Practices Assessment #21281

Merged
merged 15 commits into from
May 19, 2022
42 changes: 42 additions & 0 deletions src/azure-cli/azure/cli/command_modules/sqlvm/_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ def transform_sqlvm_output(result):
output['serverConfigurationsManagementSettings'] = format_server_configuration_management_settings(result.server_configurations_management_settings)
if result.key_vault_credential_settings is not None:
output['keyVaultCredentialSettings'] = format_key_vault_credential_settings(result.key_vault_credential_settings)
if result.assessment_settings is not None:
output['assessmentSettings'] = format_assessment_settings(result.assessment_settings)

return output
except AttributeError:
Expand Down Expand Up @@ -339,3 +341,43 @@ def format_sql_workload_type_update_settings(result):
order_dict['sqlWorkloadType'] = result.sql_workload_type

return order_dict


def format_assessment_settings(result):
'''
Formats the AssessmentSettings object removing arguments that are empty
'''
from collections import OrderedDict
# Only display parameters that have content
order_dict = OrderedDict()

if result.enable is not None:
order_dict['enable'] = result.enable

schedule = format_assessment_schedule(result.schedule)
if schedule:
order_dict['schedule'] = schedule

return order_dict


def format_assessment_schedule(result):
'''
Formats the AssessmentSchedule object removing arguments that are empty
'''

from collections import OrderedDict
# Only display parameters that have content
order_dict = OrderedDict()
if result.enable is not None:
order_dict['enable'] = result.enable
if result.weekly_interval is not None:
order_dict['weeklyInterval'] = result.weekly_interval
if result.monthly_occurrence is not None:
order_dict['monthlyOccurrence'] = result.monthly_occurrence
if result.day_of_week is not None:
order_dict['dayOfWeek'] = result.day_of_week
if result.start_time is not None:
order_dict['startTimeLocal'] = result.start_time

return order_dict
21 changes: 21 additions & 0 deletions src/azure-cli/azure/cli/command_modules/sqlvm/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,15 @@
az sql vm remove-from-group -n sqlvm -g myresourcegroup
"""

helps['sql vm start-assessment'] = """
type: command
short-summary: Starts SQL Best Practice Assessment on SQL virtual machine
examples:
- name: Starts SQL Best Practice Assessment.
text: >
az sql vm start-assessment -n sqlvm -g myresourcegroup
"""

helps['sql vm update'] = """
type: command
short-summary: Updates the properties of a SQL virtual machine.
Expand Down Expand Up @@ -149,4 +158,16 @@
- name: Update a SQL virtual machine billing tag to DR.
text: >
az sql vm update -n sqlvm -g myresourcegroup --license-type DR
- name: Update a SQL virtual machine to disable SQL Best Practice Assessment.
text: >
az sql vm update -n sqlvm -g myresourcegroup --enable-assessment false
- name: Update a SQL virtual machine to disable schedule for SQL Best Practice Assessment.
text: >
az sql vm update -n sqlvm -g myresourcegroup --enable-assessment-schedule false
- name: Update a SQL virtual machine to enable schedule with weekly interval for SQL Best Practice Assessment.
text: >
az sql vm update -n sqlvm -g myresourcegroup --enable-assessment true --enable-assessment-schedule true --assessment-weekly-interval 1 --assessment-day-of-week monday --assessment-start-time-local '19:30'
- name: Update a SQL virtual machine to enable schedule with monthly occurrence for SQL Best Practice Assessment.
text: >
az sql vm update -n sqlvm -g myresourcegroup --enable-assessment true --enable-assessment-schedule true --assessment-monthly-occurrence 1 --assessment-day-of-week monday --assessment-start-time-local '19:30'
"""
32 changes: 30 additions & 2 deletions src/azure-cli/azure/cli/command_modules/sqlvm/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
validate_public_ip_address,
validate_subnet,
validate_sqlmanagement,
validate_expand
validate_expand,
validate_assessment,
validate_assessment_start_time_local
)


Expand Down Expand Up @@ -162,7 +164,7 @@ def load_arguments(self, _):
help='Get the SQLIaaSExtension configuration settings. To view all settings, use *. To select only a few, the settings must be space-separted.',
nargs='+',
validator=validate_expand,
arg_type=get_enum_type(['*', 'AutoBackupSettings', 'AutoPatchingSettings', 'KeyVaultCredentialSettings', 'ServerConfigurationsManagementSettings']))
arg_type=get_enum_type(['*', 'AssessmentSettings', 'AutoBackupSettings', 'AutoPatchingSettings', 'KeyVaultCredentialSettings', 'ServerConfigurationsManagementSettings']))
c.argument('sql_management_mode',
help='SQL Server management type. If NoAgent selected, please provide --image-sku and --offer-type.',
options_list=['--sql-mgmt-type'],
Expand Down Expand Up @@ -318,3 +320,29 @@ def load_arguments(self, _):
c.argument('enable_r_services',
help='Enable or disable R services (SQL 2016 onwards).',
arg_type=get_three_state_flag())

with self.argument_context('sql vm update', arg_group='Assessment Settings') as c:
c.argument('enable_assessment',
help='Enable or disable assessment feature. If any assessment settings provided, parameter automatically sets to true.',
validator=validate_assessment,
arg_type=get_three_state_flag())
c.argument('enable_assessment_schedule',
options_list=['--enable-assessment-schedule', '--am-schedule'],
help='Enable or disable assessment Schedule. If any assessment schedule settings provided, parameter automatically sets to true.',
arg_type=get_three_state_flag())
c.argument('assessment_weekly_interval',
options_list=['--assessment-weekly-interval', '--am-week-int'],
help='Number of weeks to schedule between 2 assessment runs. Supports value from 1-6.',
arg_type=get_enum_type(['1', '2', '3', '4', '5', '6']))
c.argument('assessment_monthly_occurrence',
options_list=['--assessment-monthly-occurrence', '--am-month-occ'],
help='Occurence of the DayOfWeek day within a month to schedule assessment. Supports values 1,2,3,4 and -1. Use -1 for last DayOfWeek day of the month (for example - last Tuesday of the month).',
arg_type=get_enum_type(['1', '2', '3', '4', '-1']))
c.argument('assessment_day_of_week',
options_list=['--assessment-day-of-week', '--am-day'],
help='Day of the week to run assessment.',
arg_type=get_enum_type(DayOfWeek))
c.argument('assessment_start_time_local',
options_list=['--assessment-start-time-local', '--am-time'],
help='Time of the day in HH:mm format. Examples include 17:30, 05:13.',
validator=validate_assessment_start_time_local)
66 changes: 62 additions & 4 deletions src/azure-cli/azure/cli/command_modules/sqlvm/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from datetime import datetime
from msrestazure.tools import resource_id, is_valid_resource_id
from azure.cli.core.util import CLIError
from azure.cli.core.azclierror import (
InvalidArgumentValueError,
RequiredArgumentMissingError,
MutuallyExclusiveArgumentError
)
from azure.cli.core.commands.client_factory import get_subscription_id


Expand Down Expand Up @@ -83,11 +88,11 @@ def validate_subnet(cmd, namespace):
vnet = namespace.vnet_name

if vnet and '/' in vnet:
raise CLIError("incorrect usage: --subnet ID | --subnet NAME --vnet-name NAME")
raise InvalidArgumentValueError("incorrect usage: --subnet ID | --subnet NAME --vnet-name NAME")

subnet_is_id = is_valid_resource_id(subnet)
if (subnet_is_id and vnet) or (not subnet_is_id and not vnet):
raise CLIError("incorrect usage: --subnet ID | --subnet NAME --vnet-name NAME")
raise MutuallyExclusiveArgumentError("incorrect usage: --subnet ID | --subnet NAME --vnet-name NAME")

if not subnet_is_id and vnet:
namespace.subnet_resource_id = resource_id(
Expand All @@ -107,7 +112,7 @@ def validate_sqlmanagement(namespace):
sql_mgmt_mode = namespace.sql_management_mode

if (sql_mgmt_mode == "NoAgent" and (namespace.sql_image_sku is None or namespace.sql_image_offer is None)):
raise CLIError("usage error: --sql-mgmt-type NoAgent --image-sku NAME --image-offer NAME")
raise RequiredArgumentMissingError("usage error: --sql-mgmt-type NoAgent --image-sku NAME --image-offer NAME")


# pylint: disable=too-many-statements,line-too-long
Expand All @@ -117,3 +122,56 @@ def validate_expand(namespace):
'''
if namespace.expand is not None:
namespace.expand = ",".join(namespace.expand)


# pylint: disable=too-many-statements,line-too-long
def validate_assessment(namespace):
'''
Validates assessment settings
'''
enable_assessment = namespace.enable_assessment
enable_assessment_schedule = namespace.enable_assessment_schedule
assessment_weekly_interval = namespace.assessment_weekly_interval
assessment_monthly_occurrence = namespace.assessment_monthly_occurrence
assessment_day_of_week = namespace.assessment_day_of_week
assessment_start_time_local = namespace.assessment_start_time_local

is_assessment_schedule_provided = False
if (assessment_weekly_interval is not None or
assessment_weekly_interval is not None or assessment_monthly_occurrence is not None or
assessment_day_of_week is not None or assessment_start_time_local is not None):
is_assessment_schedule_provided = True

# Validate conflicting settings
if (enable_assessment_schedule is False and is_assessment_schedule_provided):
raise InvalidArgumentValueError("Assessment schedule settings cannot be provided while enable-assessment-schedule is False")

# Validate conflicting settings
if (enable_assessment is False and is_assessment_schedule_provided):
raise InvalidArgumentValueError("Assessment schedule settings cannot be provided while enable-assessment is False")

# Validate necessary fields for Assessment schedule
if is_assessment_schedule_provided:
if (assessment_weekly_interval is not None and assessment_monthly_occurrence is not None):
raise MutuallyExclusiveArgumentError("Both assessment-weekly-interval and assessment-montly-occurrence cannot be provided at the same time for Assessment schedule")
if (assessment_weekly_interval is None and assessment_monthly_occurrence is None):
raise RequiredArgumentMissingError("Either assessment-weekly-interval or assessment-montly-occurrence must be provided for Assessment schedule")
if assessment_day_of_week is None:
raise RequiredArgumentMissingError("assessment-day-of-week must be provided for Assessment schedule")
if assessment_start_time_local is None:
raise RequiredArgumentMissingError("assessment-start-time-local must be provided for Assessment schedule")


# pylint: disable=too-many-statements,line-too-long
def validate_assessment_start_time_local(namespace):
'''
Validates assessment start time format
'''
assessment_start_time_local = namespace.assessment_start_time_local

TIME_FORMAT = '%H:%M'
if assessment_start_time_local:
try:
datetime.strptime(assessment_start_time_local, TIME_FORMAT)
except ValueError:
raise InvalidArgumentValueError("assessment-start-time-local input '{}' is not valid time. Valid example: 19:30".format(assessment_start_time_local))
1 change: 1 addition & 0 deletions src/azure-cli/azure/cli/command_modules/sqlvm/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def load_command_table(self, _):
g.custom_command('remove-from-group', 'sqlvm_remove_from_group', transform=transform_sqlvm_output)
g.command('delete', 'begin_delete', confirmation=True)
g.custom_command('create', 'sqlvm_create', transform=transform_sqlvm_output, table_transformer=deployment_validate_table_format, exception_handler=handle_template_based_exception)
g.command('start-assessment', 'begin_start_assessment')

###############################################
# sql virtual machine groups #
Expand Down
48 changes: 47 additions & 1 deletion src/azure-cli/azure/cli/command_modules/sqlvm/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
SqlWorkloadTypeUpdateSettings,
AdditionalFeaturesServerConfigurations,
ServerConfigurationsManagementSettings,
Schedule,
AssessmentSettings,
SqlVirtualMachine
)

Expand Down Expand Up @@ -272,7 +274,9 @@ def sqlvm_update(instance, sql_server_license_type=None, sql_image_sku=None, ena
storage_access_key=None, backup_password=None, backup_system_dbs=False, backup_schedule_type=None, sql_management_mode=None,
full_backup_frequency=None, full_backup_start_time=None, full_backup_window_hours=None, log_backup_frequency=None,
enable_key_vault_credential=None, credential_name=None, azure_key_vault_url=None, service_principal_name=None,
service_principal_secret=None, connectivity_type=None, port=None, sql_workload_type=None, enable_r_services=None, tags=None):
service_principal_secret=None, connectivity_type=None, port=None, sql_workload_type=None, enable_r_services=None, tags=None,
enable_assessment=None, enable_assessment_schedule=None, assessment_weekly_interval=None,
assessment_monthly_occurrence=None, assessment_day_of_week=None, assessment_start_time_local=None):
'''
Updates a SQL virtual machine.
'''
Expand Down Expand Up @@ -355,6 +359,14 @@ def sqlvm_update(instance, sql_server_license_type=None, sql_image_sku=None, ena
instance.server_configurations_management_settings.additional_features_server_configurations is None):
instance.server_configurations_management_settings = None

set_assessment_properties(instance,
enable_assessment,
enable_assessment_schedule,
assessment_weekly_interval,
assessment_monthly_occurrence,
assessment_day_of_week,
assessment_start_time_local)

return instance


Expand Down Expand Up @@ -401,3 +413,37 @@ def sqlvm_remove_from_group(client, cmd, sql_virtual_machine_name, resource_grou
resource_group_name, sql_virtual_machine_name, sqlvm_object))

return client.get(resource_group_name, sql_virtual_machine_name)


# region Helpers for custom commands
def set_assessment_properties(instance, enable_assessment, enable_assessment_schedule,
assessment_weekly_interval, assessment_monthly_occurrence,
assessment_day_of_week, assessment_start_time_local):
'''
Set assessment properties to be sent in sql vm update
'''

# If assessment.schedule settings are provided but enable schedule is skipped, then ensure schedule is enabled
if (enable_assessment_schedule is None and
(assessment_weekly_interval is not None or assessment_monthly_occurrence or assessment_day_of_week or assessment_start_time_local)):
enable_assessment_schedule = True

# If assessment schedule is enabled but enable assessment is skipped, then ensure assessment is enabled
if (enable_assessment_schedule is not None and enable_assessment is None):
enable_assessment = True

if enable_assessment is not None:
instance.assessment_settings = AssessmentSettings()
instance.assessment_settings.enable = enable_assessment

if enable_assessment_schedule is not None:
instance.assessment_settings.schedule = Schedule()
instance.assessment_settings.schedule.enable = enable_assessment_schedule

if enable_assessment_schedule:
instance.assessment_settings.schedule.weekly_interval = assessment_weekly_interval
instance.assessment_settings.schedule.monthly_occurrence = assessment_monthly_occurrence
instance.assessment_settings.schedule.day_of_week = assessment_day_of_week
instance.assessment_settings.schedule.start_time = assessment_start_time_local

# endRegion
Loading