diff --git a/src/command_modules/azure-cli-sql/azure/cli/command_modules/sql/_util.py b/src/command_modules/azure-cli-sql/azure/cli/command_modules/sql/_util.py index 12b935590dd..62cb9893bca 100644 --- a/src/command_modules/azure-cli-sql/azure/cli/command_modules/sql/_util.py +++ b/src/command_modules/azure-cli-sql/azure/cli/command_modules/sql/_util.py @@ -32,6 +32,14 @@ def get_sql_recommended_elastic_pools_operations(kwargs): return get_sql_management_client(kwargs).recommended_elastic_pools +def get_sql_database_blob_auditing_policies_operations(kwargs): + return get_sql_management_client(kwargs).database_blob_auditing_policies + + +def get_sql_database_threat_detection_policies_operations(kwargs): + return get_sql_management_client(kwargs).database_threat_detection_policies + + # COMMANDS UTILITIES def create_service_adapter(service_model, service_class): @@ -86,7 +94,9 @@ def custom_command(self, name, custom_func_name, confirmation=None): client_factory=self._client_factory, confirmation=confirmation) - def generic_update_command(self, name, getter_op, setter_op, custom_func_name=None): + # pylint: disable=too-many-arguments + def generic_update_command(self, name, getter_op, setter_op, custom_func_name=None, + setter_arg_name='parameters'): if custom_func_name: custom_function_op = self._custom_path.format(custom_func_name) else: @@ -98,7 +108,8 @@ def generic_update_command(self, name, getter_op, setter_op, custom_func_name=No self._service_adapter(getter_op), self._service_adapter(setter_op), factory=self._client_factory, - custom_function_op=custom_function_op) + custom_function_op=custom_function_op, + setter_arg_name=setter_arg_name) # PARAMETERS UTILITIES diff --git a/src/command_modules/azure-cli-sql/azure/cli/command_modules/sql/commands.py b/src/command_modules/azure-cli-sql/azure/cli/command_modules/sql/commands.py index 6b287254e76..e7ceeb2e589 100644 --- a/src/command_modules/azure-cli-sql/azure/cli/command_modules/sql/commands.py +++ b/src/command_modules/azure-cli-sql/azure/cli/command_modules/sql/commands.py @@ -3,8 +3,14 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- -from ._util import (get_sql_servers_operation, get_sql_database_operations, - get_sql_elasticpools_operations, create_service_adapter, ServiceGroup) +from ._util import ( + get_sql_servers_operation, + get_sql_database_operations, + get_sql_database_blob_auditing_policies_operations, + get_sql_database_threat_detection_policies_operations, + get_sql_elasticpools_operations, + create_service_adapter, + ServiceGroup) ############################################### # sql db # @@ -59,6 +65,33 @@ # c.command('list', 'list_service_tier_advisors') # c.command('show', 'get_service_tier_advisor') +database_blob_auditing_policy_operations = create_service_adapter( + 'azure.mgmt.sql.operations.database_blob_auditing_policies_operations', + 'DatabaseBlobAuditingPoliciesOperations') + +with ServiceGroup(__name__, + get_sql_database_blob_auditing_policies_operations, + database_blob_auditing_policy_operations) as s: + with s.group('sql db audit-policy') as c: + c.command('show', 'get') + c.generic_update_command( + 'update', 'get', 'create_or_update', + custom_func_name='db_audit_policy_update', + setter_arg_name='database_blob_auditing_policy') + +database_threat_detection_policy_operations = create_service_adapter( + 'azure.mgmt.sql.operations.database_threat_detection_policies_operations', + 'DatabaseThreatDetectionPoliciesOperations') + +with ServiceGroup(__name__, + get_sql_database_threat_detection_policies_operations, + database_threat_detection_policy_operations) as s: + with s.group('sql db threat-policy') as c: + c.command('show', 'get') + c.generic_update_command('update', 'get', 'create_or_update', + custom_func_name='db_threat_detection_policy_update', + setter_arg_name='database_security_alert_policy') + ############################################### # sql elastic-pool # ############################################### diff --git a/src/command_modules/azure-cli-sql/azure/cli/command_modules/sql/custom.py b/src/command_modules/azure-cli-sql/azure/cli/command_modules/sql/custom.py index 56c915baa8f..223fcdb2280 100644 --- a/src/command_modules/azure-cli-sql/azure/cli/command_modules/sql/custom.py +++ b/src/command_modules/azure-cli-sql/azure/cli/command_modules/sql/custom.py @@ -8,14 +8,23 @@ get_sql_elasticpools_operations ) -from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.core.commands.client_factory import ( + get_mgmt_service_client, + get_subscription_id) from azure.cli.core._util import CLIError from azure.mgmt.sql.models.sql_management_client_enums import ( + BlobAuditingPolicyState, CreateMode, DatabaseEditions, ReplicationRole, - ServiceObjectiveName, + SecurityAlertPolicyState, + ServiceObjectiveName ) +from azure.mgmt.resource.resources import ResourceManagementClient +from azure.mgmt.storage import StorageManagementClient + +# url parse package has different names in Python 2 and 3. 'six' package works cross-version. +from six.moves.urllib.parse import (quote, urlparse) # pylint: disable=import-error ############################################### # Common funcs # @@ -98,8 +107,6 @@ def _db_create_special( resource_group_name=dest_db.resource_group_name) # Set create mode properties - # url parse package has different names in Python 2 and 3. 'six' package works cross-version. - from six.moves.urllib.parse import quote # pylint: disable=import-error subscription_id = get_subscription_id() kwargs['source_database_id'] = ( '/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Sql/servers/{}/databases/{}' @@ -336,6 +343,207 @@ def db_update( return instance +##### +# sql server audit-policy & threat-policy +##### + + +# Finds a storage account's resource group by querying ARM resource cache. +# Why do we have to do this: so we know the resource group in order to later query the storage API +# to determine the account's keys and endpoint. Why isn't this just a command line parameter: +# because if it was a command line parameter then the customer would need to specify storage +# resource group just to update some unrelated property, which is annoying and makes no sense to +# the customer. +def _find_storage_account_resource_group(name): + storage_type = 'Microsoft.Storage/storageAccounts' + classic_storage_type = 'Microsoft.ClassicStorage/storageAccounts' + + query = "name eq '{}' and (resourceType eq '{}' or resourceType eq '{}')".format( + name, storage_type, classic_storage_type) + + client = get_mgmt_service_client(ResourceManagementClient) + resources = list(client.resources.list(filter=query)) + + if len(resources) == 0: + raise CLIError("No storage account with name '{}' was found.".format(name)) + + if len(resources) > 1: + raise CLIError("Multiple storage accounts with name '{}' were found.".format(name)) + + if resources[0].type == classic_storage_type: + raise CLIError("The storage account with name '{}' is a classic storage account which is" + " not supported by this command. Use a non-classic storage account or" + " specify storage endpoint and key instead.".format(name)) + + # Split the uri and return just the resource group + return resources[0].id.split('/')[4] + + +# Determines storage account name from endpoint url string. +# e.g. 'https://mystorage.blob.core.windows.net' -> 'mystorage' +def _get_storage_account_name(storage_endpoint): + return urlparse(storage_endpoint).netloc.split('.')[0] + + +# Gets storage account key by querying storage ARM API. +def _get_storage_endpoint( + storage_account, + resource_group_name): + + # Get storage account + client = get_mgmt_service_client(StorageManagementClient) + account = client.storage_accounts.get_properties( + resource_group_name=resource_group_name, + account_name=storage_account) + + # Get endpoint + # pylint: disable=no-member + endpoints = account.primary_endpoints + try: + return endpoints.blob + except AttributeError: + raise CLIError("The storage account with name '{}' (id '{}') has no blob endpoint. Use a" + " different storage account.".format(account.name, account.id)) + + +# Gets storage account key by querying storage ARM API. +def _get_storage_key( + storage_account, + resource_group_name, + use_secondary_key): + + # Get storage keys + client = get_mgmt_service_client(StorageManagementClient) + keys = client.storage_accounts.list_keys( + resource_group_name=resource_group_name, + account_name=storage_account) + + # Choose storage key + index = 1 if use_secondary_key else 0 + return keys.keys[index].value # pylint: disable=no-member + + +# Common code for updating audit and threat detection policy +def _db_security_policy_update( # pylint: disable=too-many-arguments + instance, + enabled, + storage_account, + storage_endpoint, + storage_account_access_key, + use_secondary_key): + + # Validate storage endpoint arguments + if storage_endpoint is not None and storage_account is not None: + raise CLIError('--storage-endpoint and --storage-account cannot both be specified.') + + # Set storage endpoint + if storage_endpoint is not None: + instance.storage_endpoint = storage_endpoint + if storage_account is not None: + storage_resource_group = _find_storage_account_resource_group(storage_account) + instance.storage_endpoint = _get_storage_endpoint(storage_account, storage_resource_group) + + # Set storage access key + if storage_account_access_key is not None: + # Access key is specified + instance.storage_account_access_key = storage_account_access_key + elif enabled: + # Access key is not specified, but state is Enabled. + # If state is Enabled, then access key property is required in PUT. However access key is + # readonly (GET returns empty string for access key), so we need to determine the value + # and then PUT it back. (We don't want the user to be force to specify this, because that + # would be very annoying when updating non-storage-related properties). + # This doesn't work if the user used generic update args, i.e. `--set state=Enabled` + # instead of `--state Enabled`, since the generic update args are applied after this custom + # function, but at least we tried. + if storage_account is None: + storage_account = _get_storage_account_name(instance.storage_endpoint) + storage_resource_group = _find_storage_account_resource_group(storage_account) + + instance.storage_account_access_key = _get_storage_key( + storage_account, + storage_resource_group, + use_secondary_key) + + +# Update audit policy. Custom update function to apply parameters to instance. +def db_audit_policy_update( # pylint: disable=too-many-arguments + instance, + state=None, + storage_account=None, + storage_endpoint=None, + storage_account_access_key=None, + audit_actions_and_groups=None, + retention_days=None): + + # Apply state + if state is not None: + # pylint: disable=unsubscriptable-object + instance.state = BlobAuditingPolicyState[state.lower()] + enabled = instance.state.value.lower() == BlobAuditingPolicyState.enabled.value.lower() + + # Set storage-related properties + _db_security_policy_update( + instance, + enabled, + storage_account, + storage_endpoint, + storage_account_access_key, + instance.is_storage_secondary_key_in_use) + + # Set other properties + if audit_actions_and_groups is not None: + instance.audit_actions_and_groups = audit_actions_and_groups + + if retention_days is not None: + instance.retention_days = retention_days + + return instance + + +# Update threat detection policy. Custom update function to apply parameters to instance. +def db_threat_detection_policy_update( # pylint: disable=too-many-arguments + instance, + state=None, + storage_account=None, + storage_endpoint=None, + storage_account_access_key=None, + retention_days=None, + email_addresses=None, + disabled_alerts=None, + email_account_admins=None): + + # Apply state + if state is not None: + # pylint: disable=unsubscriptable-object + instance.state = SecurityAlertPolicyState[state.lower()] + enabled = instance.state.value.lower() == SecurityAlertPolicyState.enabled.value.lower() + + # Set storage-related properties + _db_security_policy_update( + instance, + enabled, + storage_account, + storage_endpoint, + storage_account_access_key, + False) + + # Set other properties + if retention_days is not None: + instance.retention_days = retention_days + + if email_addresses is not None: + instance.email_addresses = ";".join(email_addresses) + + if disabled_alerts is not None: + instance.disabled_alerts = ";".join(disabled_alerts) + + if email_account_admins is not None: + instance.email_account_admins = email_account_admins + + return instance + + ############################################### # sql dw # ############################################### diff --git a/src/command_modules/azure-cli-sql/azure/cli/command_modules/sql/help.py b/src/command_modules/azure-cli-sql/azure/cli/command_modules/sql/help.py index 382ea39f3a3..85496be5b32 100644 --- a/src/command_modules/azure-cli-sql/azure/cli/command_modules/sql/help.py +++ b/src/command_modules/azure-cli-sql/azure/cli/command_modules/sql/help.py @@ -8,65 +8,123 @@ # pylint: disable=line-too-long helps['sql'] = """ - type: group - short-summary: Manage Azure SQL Databases and Data Warehouses. - """ + type: group + short-summary: Manage Azure SQL Databases and Data Warehouses. + """ helps['sql db'] = """ - type: group - short-summary: Manage databases. - """ + type: group + short-summary: Manage databases. + """ helps['sql db copy'] = """ - type: command - short-summary: Creates a copy of an existing database. - """ + type: command + short-summary: Creates a copy of an existing database. + """ helps['sql db create'] = """ - type: command - short-summary: Creates a database. - """ + type: command + short-summary: Creates a database. + """ helps['sql db delete'] = """ - type: command - short-summary: Deletes a database or data warehouse. - """ + type: command + short-summary: Deletes a database or data warehouse. + """ helps['sql db list'] = """ - type: command - short-summary: Lists all databases and data warehouses in a server, or all databases in an elastic pool. - """ + type: command + short-summary: Lists all databases and data warehouses in a server, or all databases in an elastic pool. + """ helps['sql db show'] = """ - type: command - short-summary: Gets a database or data warehouse. - """ + type: command + short-summary: Gets a database or data warehouse. + """ helps['sql db update'] = """ - type: command - short-summary: Updates a database. - """ + type: command + short-summary: Updates a database. + """ +helps['sql db audit-policy'] = """ + type: group + short-summary: Manage a database's auditing policy. + """ +helps['sql db audit-policy update'] = """ + type: command + short-summary: Updates a database's auditing policy. + long-summary: If the policy is being enabled, storage_account or both storage_endpoint and + storage_account_access_key must be specified. + examples: + - name: Enable by specifying storage account name + text: az sql db audit-policy update -g mygroup -s myserver -n mydb + --state Enabled --storage-account mystorage + - name: Enable by specifying storage endpoint and key + text: az sql db audit-policy update -g mygroup -s myserver -n mydb + --state Enabled --storage-endpoint https://mystorage.blob.core.windows.net + --storage-key MYKEY== + - name: Set the list of audit actions + text: az sql db audit-policy update -g mygroup -s myserver -n mydb + --actions FAILED_DATABASE_AUTHENTICATION_GROUP 'UPDATE on database::mydb by public' + - name: Add an audit action + text: az sql db audit-policy update -g mygroup -s myserver -n mydb + --add auditActionsAndGroups FAILED_DATABASE_AUTHENTICATION_GROUP + - name: Remove an audit action by list index + text: az sql db audit-policy update -g mygroup -s myserver -n mydb + --remove auditActionsAndGroups 0 + - name: Disable an auditing policy + text: az sql db audit-policy update -g mygroup -s myserver -n mydb + --state Disabled + """ helps['sql db replica'] = """ - type: group - short-summary: Manage replication between databases. - """ + type: group + short-summary: Manage replication between databases. + """ helps['sql db replica create'] = """ - type: command - short-summary: Creates a database as a readable secondary replica of an existing database. - """ + type: command + short-summary: Creates a database as a readable secondary replica of an existing database. + """ helps['sql db replica set-primary'] = """ - type: command - short-summary: Sets which replica database is primary by failing over from the current primary replica database. - """ + type: command + short-summary: Sets which replica database is primary by failing over from the current primary replica database. + """ helps['sql db replica list-links'] = """ - type: command - short-summary: Lists the replicas of a database and corresponding replication status. - """ + type: command + short-summary: Lists the replicas of a database and corresponding replication status. + """ helps['sql db replica delete-link'] = """ - type: command - short-summary: Permanently stops data replication between two database replicas. - """ + type: command + short-summary: Permanently stops data replication between two database replicas. + """ helps['sql db restore'] = """ - type: command - short-summary: Creates a new database by restoring from a database backup. - """ + type: command + short-summary: Creates a new database by restoring from a database backup. + """ helps['sql db import'] = """ - type: command - short-summary: Imports a bacpac into an existing database. - """ + type: command + short-summary: Imports a bacpac into an existing database. + """ +helps['sql db threat-policy'] = """ + type: group + short-summary: Manage a database's threat detection policy. + """ +helps['sql db threat-policy update'] = """ + type: command + short-summary: Updates a database's threat detection policy. + long-summary: If the policy is being enabled, storage_account or both storage_endpoint and + storage_account_access_key must be specified. + examples: + - name: Enable by specifying storage account name + text: az sql db threat-policy update -g mygroup -s myserver -n mydb + --state Enabled --storage-account mystorage + - name: Enable by specifying storage endpoint and key + text: az sql db threat-policy update -g mygroup -s myserver -n mydb + --state Enabled --storage-endpoint https://mystorage.blob.core.windows.net + --storage-key MYKEY== + - name: Disable a subset of alert types + text: az sql db threat-policy update -g mygroup -s myserver -n mydb + --disabled-alerts Sql_Injection_Vulnerability Access_Anomaly + - name: Configure email recipients + text: az sql db threat-policy update -g mygroup -s myserver -n mydb + --email-addresses me@examlee.com you@example.com --email-account-admins + Enabled + - name: Disable + text: az sql db threat-policy update -g mygroup -s myserver -n mydb + --state Disabled + """ # helps['sql db restore-point'] = """ # type: group # short-summary: Manage database restore points. @@ -80,41 +138,41 @@ # short-summary: Manage database service tier advisors. # """ helps['sql dw'] = """ - type: group - short-summary: Manage data warehouses. - """ + type: group + short-summary: Manage data warehouses. + """ helps['sql dw create'] = """ - type: command - short-summary: Creates a data warehouse. - """ + type: command + short-summary: Creates a data warehouse. + """ helps['sql dw delete'] = """ - type: command - short-summary: Deletes a database or data warehouse. - """ + type: command + short-summary: Deletes a database or data warehouse. + """ helps['sql dw list'] = """ - type: command - short-summary: Lists all data warehouses in a server. - """ + type: command + short-summary: Lists all data warehouses in a server. + """ helps['sql dw show'] = """ - type: command - short-summary: Gets a database or data warehouse. - """ + type: command + short-summary: Gets a database or data warehouse. + """ helps['sql dw update'] = """ - type: command - short-summary: Updates a data warehouse. - """ + type: command + short-summary: Updates a data warehouse. + """ helps['sql elastic-pool'] = """ - type: group - short-summary: Manage elastic pools. An elastic pool is an allocation of CPU, IO, and memory resources. Databases inside the pool share these resources. - """ + type: group + short-summary: Manage elastic pools. An elastic pool is an allocation of CPU, IO, and memory resources. Databases inside the pool share these resources. + """ helps['sql elastic-pool create'] = """ - type: command - short-summary: Creates an elastic pool. - """ + type: command + short-summary: Creates an elastic pool. + """ helps['sql elastic-pool update'] = """ - type: command - short-summary: Updates an elastic pool. - """ + type: command + short-summary: Updates an elastic pool. + """ # helps['sql elastic-pool recommended'] = """ # type: group # short-summary: Manages recommended elastic pools. @@ -124,42 +182,42 @@ # short-summary: Manage recommended elastic pool databases. # """ helps['sql server'] = """ - type: group - short-summary: Manage servers. Servers contain databases, data warehouses, and elastic pools. - """ + type: group + short-summary: Manage servers. Servers contain databases, data warehouses, and elastic pools. + """ helps['sql server create'] = """ - type: command - short-summary: Creates a server. - """ + type: command + short-summary: Creates a server. + """ helps['sql server list'] = """ - type: command - short-summary: Lists servers. - """ + type: command + short-summary: Lists servers. + """ helps['sql server update'] = """ - type: command - short-summary: Updates a server. - """ + type: command + short-summary: Updates a server. + """ helps['sql server firewall-rule'] = """ - type: group - short-summary: Manage a server's firewall rules. - """ + type: group + short-summary: Manage a server's firewall rules. + """ # helps['sql server firewall-rule allow-all-azure-ips'] = """ # type: command # short-summary: Create a firewall rule that allows all Azure IP addresses to access the server. # """ helps['sql server firewall-rule create'] = """ - type: command - short-summary: Creates a firewall rule. - """ + type: command + short-summary: Creates a firewall rule. + """ helps['sql server firewall-rule update'] = """ - type: command - short-summary: Updates a firewall rule. - """ + type: command + short-summary: Updates a firewall rule. + """ helps['sql server firewall-rule show'] = """ - type: command - short-summary: Shows the details of a firewall rule. - """ + type: command + short-summary: Shows the details of a firewall rule. + """ helps['sql server firewall-rule list'] = """ - type: command - short-summary: Lists the firewall rules. - """ + type: command + short-summary: Lists the firewall rules. + """ diff --git a/src/command_modules/azure-cli-sql/azure/cli/command_modules/sql/params.py b/src/command_modules/azure-cli-sql/azure/cli/command_modules/sql/params.py index 0bcccabe575..4d88d90c0b1 100644 --- a/src/command_modules/azure-cli-sql/azure/cli/command_modules/sql/params.py +++ b/src/command_modules/azure-cli-sql/azure/cli/command_modules/sql/params.py @@ -7,17 +7,23 @@ from enum import Enum from ._util import ParametersContext, patch_arg_make_required from azure.cli.core.commands import CliArgumentType -from azure.cli.core.commands.parameters import enum_choice_list -from azure.cli.core.commands.parameters import ignore_type +from azure.cli.core.commands.parameters import ( + enum_choice_list, + ignore_type) from azure.mgmt.sql.models.database import Database from azure.mgmt.sql.models.elastic_pool import ElasticPool -from azure.mgmt.sql.models.server import Server from azure.mgmt.sql.models.import_extension_request_parameters \ import ImportExtensionRequestParameters from azure.mgmt.sql.models.export_request_parameters import ExportRequestParameters -from azure.mgmt.sql.models.sql_management_client_enums import CreateMode -from azure.mgmt.sql.models.sql_management_client_enums import StorageKeyType -from azure.mgmt.sql.models.sql_management_client_enums import AuthenticationType +from azure.mgmt.sql.models.server import Server +from azure.mgmt.sql.models.sql_management_client_enums import ( + AuthenticationType, + BlobAuditingPolicyState, + CreateMode, + SecurityAlertPolicyState, + SecurityAlertPolicyEmailAccountAdmins, + StorageKeyType) + ##### # Reusable param type definitions @@ -137,6 +143,9 @@ def _configure_db_create_params( if create_mode not in [CreateMode.restore, CreateMode.point_in_time_restore]: cmd.ignore('restore_point_in_time') + # Only applicable to restore create mode. However using this from CLI isn't tested yet. + cmd.ignore('source_database_deletion_date') + # 'collation', 'edition', and 'max_size_bytes' are ignored (or rejected) when creating a copy # or secondary because their values are determined by the source db. if create_mode in [CreateMode.copy, CreateMode.non_readable_secondary, @@ -158,6 +167,10 @@ def _configure_db_create_params( # Edition is always 'DataWarehouse' c.ignore('edition') + # recovery_services_recovery_point_resource_id is only for long-term-retention restore + if create_mode != CreateMode.restore_long_term_retention_backup: + c.ignore('recovery_services_recovery_point_resource_id') + with ParametersContext(command='sql db') as c: c.argument('database_name', @@ -282,7 +295,11 @@ def _configure_db_create_params( c.argument('authentication_type', options_list=('--auth_type',), **enum_choice_list(AuthenticationType)) c.argument('storage_key_type', **enum_choice_list(StorageKeyType)) - c.argument('name', options_list=('--slkdjflksdjf',), arg_type=ignore_type) + + # The parameter name '--name' is used for 'database_name', so we need to give a different name + # for the import extension 'name' parameter to avoid conflicts. This parameter is actually not + # needed, but we still need to avoid this conflict. + c.argument('name', options_list=('--unused-extension-name',), arg_type=ignore_type) ##### @@ -333,18 +350,82 @@ def _configure_db_create_params( ##### -# sql db <> +# sql db audit-policy & threat-policy ##### +def _configure_security_policy_storage_params(cmd): + storage_arg_group = 'Storage' -# Service tier advisor will not be included in the first batch of GA commands -# with ParametersContext(command='sql db service-tier-advisor') as c: -# c.register_alias('database_name', ('--database', '-d')) + cmd.argument('storage_account', + options_list=('--storage-account',), + arg_group=storage_arg_group, + help='Name of the storage account.') -# TDE will not be included in the first batch of GA commands -# with ParametersContext(command='sql db transparent-data-encryption') as c: -# c.register_alias('database_name', ('--database', '-d')) + cmd.argument('storage_account_access_key', + options_list=('--storage-key',), + arg_group=storage_arg_group, + help='Access key for the storage account.') + + cmd.argument('storage_endpoint', + arg_group=storage_arg_group, + help='The storage account endpoint.') + + +with ParametersContext(command='sql db audit-policy update') as c: + _configure_security_policy_storage_params(c) + + policy_arg_group = 'Policy' + + c.argument('state', + arg_group=policy_arg_group, + help='Auditing policy state', + **enum_choice_list(BlobAuditingPolicyState)) + + c.argument('audit_actions_and_groups', + options_list=('--actions',), + arg_group=policy_arg_group, + help='List of actions and action groups to audit.', + nargs='+') + + c.argument('retention_days', + arg_group=policy_arg_group, + help='The number of days to retain audit logs.') + + +with ParametersContext(command='sql db threat-policy update') as c: + _configure_security_policy_storage_params(c) + + policy_arg_group = 'Policy' + notification_arg_group = 'Notification' + + c.argument('state', + arg_group=policy_arg_group, + help='Threat detection policy state', + **enum_choice_list(SecurityAlertPolicyState)) + + c.argument('retention_days', + arg_group=policy_arg_group, + help='The number of days to retain threat detection logs.') + + c.argument('disabled_alerts', + arg_group=policy_arg_group, + options_list=('--disabled-alerts',), + help='List of disabled alerts.', + nargs='+') + + c.argument('email_addresses', + arg_group=notification_arg_group, + options_list=('--email-addresses',), + help='List of email addresses that alerts are sent to.', + nargs='+') + + c.argument('email_account_admins', + arg_group=notification_arg_group, + options_list=('--email-account-admins',), + help='Whether the alert is sent to the account administrators.', + **enum_choice_list(SecurityAlertPolicyEmailAccountAdmins)) + # TODO: use server default ############################################### # sql dw # diff --git a/src/command_modules/azure-cli-sql/setup.py b/src/command_modules/azure-cli-sql/setup.py index 24515972d86..73acc436cb7 100644 --- a/src/command_modules/azure-cli-sql/setup.py +++ b/src/command_modules/azure-cli-sql/setup.py @@ -24,7 +24,8 @@ DEPENDENCIES = [ 'azure-cli-core', - 'azure-mgmt-sql==0.3.2', + 'azure-mgmt-sql==0.3.3', + 'azure-mgmt-storage==0.31.0', 'six' ] diff --git a/src/command_modules/azure-cli-sql/tests/recordings/test_sql_db_security_mgmt.yaml b/src/command_modules/azure-cli-sql/tests/recordings/test_sql_db_security_mgmt.yaml new file mode 100644 index 00000000000..de9a97cc959 --- /dev/null +++ b/src/command_modules/azure-cli-sql/tests/recordings/test_sql_db_security_mgmt.yaml @@ -0,0 +1,1103 @@ +interactions: +- request: + body: '{"location": "westus", "tags": {"use": "az-test"}}' + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [group create] + Connection: [keep-alive] + Content-Length: ['50'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 resourcemanagementclient/0.30.2 Azure-SDK-For-Python + AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001?api-version=2016-09-01 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001","name":"clitest.rg000001","location":"westus","tags":{"use":"az-test"},"properties":{"provisioningState":"Succeeded"}}'} + headers: + cache-control: [no-cache] + content-length: ['326'] + content-type: [application/json; charset=utf-8] + date: ['Tue, 21 Mar 2017 16:40:40 GMT'] + expires: ['-1'] + pragma: [no-cache] + strict-transport-security: [max-age=31536000; includeSubDomains] + x-ms-ratelimit-remaining-subscription-writes: ['1199'] + status: {code: 201, message: Created} +- request: + body: '{"location": "westus", "tags": {"use": "az-test"}}' + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [group create] + Connection: [keep-alive] + Content-Length: ['50'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 resourcemanagementclient/0.30.2 Azure-SDK-For-Python + AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000002?api-version=2016-09-01 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000002","name":"clitest.rg000002","location":"westus","tags":{"use":"az-test"},"properties":{"provisioningState":"Succeeded"}}'} + headers: + cache-control: [no-cache] + content-length: ['326'] + content-type: [application/json; charset=utf-8] + date: ['Tue, 21 Mar 2017 16:40:43 GMT'] + expires: ['-1'] + pragma: [no-cache] + strict-transport-security: [max-age=31536000; includeSubDomains] + x-ms-ratelimit-remaining-subscription-writes: ['1199'] + status: {code: 201, message: Created} +- request: + body: '{"location": "westus", "properties": {"administratorLoginPassword": "SecretPassword123", + "administratorLogin": "admin123"}}' + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql server create] + Connection: [keep-alive] + Content-Length: ['123'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 sqlmanagementclient/0.3.3 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003?api-version=2014-04-01 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003","name":"clitestserver000003","type":"Microsoft.Sql/servers","location":"West + US","kind":"v12.0","properties":{"fullyQualifiedDomainName":"clitestserver000003.database.windows.net","administratorLogin":"admin123","administratorLoginPassword":"SecretPassword123","externalAdministratorLogin":null,"externalAdministratorSid":null,"version":"12.0","state":"Ready"}}'} + headers: + cache-control: ['no-store, no-cache'] + content-length: ['695'] + content-type: [application/json; odata=minimalmetadata; streaming=true; charset=utf-8] + dataserviceversion: [3.0;] + date: ['Tue, 21 Mar 2017 16:41:15 GMT'] + preference-applied: [return-content] + server: [Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + x-content-type-options: [nosniff] + x-ms-ratelimit-remaining-subscription-writes: ['1199'] + status: {code: 201, message: Created} +- request: + body: '{"location": "westus", "sku": {"name": "Standard_LRS"}, "kind": "Storage"}' + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [storage account create] + Connection: [keep-alive] + Content-Length: ['74'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 storagemanagementclient/0.31.0 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000004?api-version=2016-12-01 + response: + body: {string: ''} + headers: + cache-control: [no-cache] + content-length: ['0'] + date: ['Tue, 21 Mar 2017 16:41:24 GMT'] + expires: ['-1'] + location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Storage/operations/b9d4dc53-2d24-4187-b1a5-263fb04766c2?monitor=true&api-version=2016-12-01'] + pragma: [no-cache] + retry-after: ['17'] + server: [Microsoft-Azure-Storage-Resource-Provider/1.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + x-ms-ratelimit-remaining-subscription-writes: ['1199'] + status: {code: 202, message: Accepted} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [storage account create] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 storagemanagementclient/0.31.0 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Storage/operations/b9d4dc53-2d24-4187-b1a5-263fb04766c2?monitor=true&api-version=2016-12-01 + response: + body: {string: ''} + headers: + cache-control: [no-cache] + content-length: ['0'] + date: ['Tue, 21 Mar 2017 16:41:42 GMT'] + expires: ['-1'] + location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Storage/operations/b9d4dc53-2d24-4187-b1a5-263fb04766c2?monitor=true&api-version=2016-12-01'] + pragma: [no-cache] + retry-after: ['17'] + server: [Microsoft-Azure-Storage-Resource-Provider/1.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + status: {code: 202, message: Accepted} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [storage account create] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 storagemanagementclient/0.31.0 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Storage/operations/b9d4dc53-2d24-4187-b1a5-263fb04766c2?monitor=true&api-version=2016-12-01 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000004","kind":"Storage","location":"westus","name":"clitest000004","properties":{"creationTime":"2017-03-21T16:41:17.6105411Z","primaryEndpoints":{"blob":"https://clitest000004.blob.core.windows.net/","file":"https://clitest000004.file.core.windows.net/","queue":"https://clitest000004.queue.core.windows.net/","table":"https://clitest000004.table.core.windows.net/"},"primaryLocation":"westus","provisioningState":"Succeeded","statusOfPrimary":"available"},"sku":{"name":"Standard_LRS","tier":"Standard"},"tags":{},"type":"Microsoft.Storage/storageAccounts"} + + '} + headers: + cache-control: [no-cache] + content-length: ['827'] + content-type: [application/json] + date: ['Tue, 21 Mar 2017 16:41:59 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-Azure-Storage-Resource-Provider/1.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: '{"location": "westus", "sku": {"name": "Standard_LRS"}, "kind": "Storage"}' + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [storage account create] + Connection: [keep-alive] + Content-Length: ['74'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 storagemanagementclient/0.31.0 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000002/providers/Microsoft.Storage/storageAccounts/clitest000005?api-version=2016-12-01 + response: + body: {string: ''} + headers: + cache-control: [no-cache] + content-length: ['0'] + date: ['Tue, 21 Mar 2017 16:42:02 GMT'] + expires: ['-1'] + location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Storage/operations/4c4a814e-67e0-49c3-bbed-d9f6727617df?monitor=true&api-version=2016-12-01'] + pragma: [no-cache] + retry-after: ['17'] + server: [Microsoft-Azure-Storage-Resource-Provider/1.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + x-ms-ratelimit-remaining-subscription-writes: ['1198'] + status: {code: 202, message: Accepted} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [storage account create] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 storagemanagementclient/0.31.0 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Storage/operations/4c4a814e-67e0-49c3-bbed-d9f6727617df?monitor=true&api-version=2016-12-01 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000002/providers/Microsoft.Storage/storageAccounts/clitest000005","kind":"Storage","location":"westus","name":"clitest000005","properties":{"creationTime":"2017-03-21T16:42:01.7892993Z","primaryEndpoints":{"blob":"https://clitest000005.blob.core.windows.net/","file":"https://clitest000005.file.core.windows.net/","queue":"https://clitest000005.queue.core.windows.net/","table":"https://clitest000005.table.core.windows.net/"},"primaryLocation":"westus","provisioningState":"Succeeded","statusOfPrimary":"available"},"sku":{"name":"Standard_LRS","tier":"Standard"},"tags":{},"type":"Microsoft.Storage/storageAccounts"} + + '} + headers: + cache-control: [no-cache] + content-length: ['827'] + content-type: [application/json] + date: ['Tue, 21 Mar 2017 16:42:20 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-Azure-Storage-Resource-Provider/1.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [storage account show] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 storagemanagementclient/0.31.0 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000004?api-version=2016-12-01 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000004","kind":"Storage","location":"westus","name":"clitest000004","properties":{"creationTime":"2017-03-21T16:41:17.6105411Z","primaryEndpoints":{"blob":"https://clitest000004.blob.core.windows.net/","file":"https://clitest000004.file.core.windows.net/","queue":"https://clitest000004.queue.core.windows.net/","table":"https://clitest000004.table.core.windows.net/"},"primaryLocation":"westus","provisioningState":"Succeeded","statusOfPrimary":"available"},"sku":{"name":"Standard_LRS","tier":"Standard"},"tags":{},"type":"Microsoft.Storage/storageAccounts"} + + '} + headers: + cache-control: [no-cache] + content-length: ['827'] + content-type: [application/json] + date: ['Tue, 21 Mar 2017 16:42:22 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-Azure-Storage-Resource-Provider/1.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [storage account keys list] + Connection: [keep-alive] + Content-Length: ['0'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 storagemanagementclient/0.31.0 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: POST + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000004/listKeys?api-version=2016-12-01 + response: + body: {string: '{"keys":[{"keyName":"key1","permissions":"Full","value":"XWb0CfQ1vjVmN2+aU/b1eiKBO1FzJhxkTv2mbp5Ryvucdgv733I+pVm8DeNxt+pxUnN+RrRga97uVCe1xIzc9A=="},{"keyName":"key2","permissions":"Full","value":"umNsm4VVyfShpkaQu685eHJLShyRFN4sDG+x2xSkecrFoN6hZE83tvSr1zAJyJ9R1p69FI5LLl1CZHmRaKAjVQ=="}]} + + '} + headers: + cache-control: [no-cache] + content-length: ['289'] + content-type: [application/json] + date: ['Tue, 21 Mar 2017 16:42:24 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-Azure-Storage-Resource-Provider/1.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-ms-ratelimit-remaining-subscription-writes: ['1199'] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db create] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 sqlmanagementclient/0.3.3 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003?api-version=2014-04-01 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003","name":"clitestserver000003","type":"Microsoft.Sql/servers","location":"West + US","kind":"v12.0","properties":{"fullyQualifiedDomainName":"clitestserver000003.database.windows.net","administratorLogin":"admin123","administratorLoginPassword":null,"externalAdministratorLogin":null,"externalAdministratorSid":null,"version":"12.0","state":"Ready"}}'} + headers: + cache-control: ['no-store, no-cache'] + content-length: ['680'] + content-type: [application/json; odata=minimalmetadata; streaming=true; charset=utf-8] + dataserviceversion: [3.0;] + date: ['Tue, 21 Mar 2017 16:42:25 GMT'] + server: [Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-content-type-options: [nosniff] + status: {code: 200, message: OK} +- request: + body: '{"location": "West US"}' + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db create] + Connection: [keep-alive] + Content-Length: ['23'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 sqlmanagementclient/0.3.3 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01?api-version=2014-04-01 + response: + body: {string: '{"operation":"CreateLogicalDatabase","startTime":"\/Date(1490114549119+0000)\/"}'} + headers: + azure-asyncoperation: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/azureAsyncOperation/ad716bef-686e-437e-babc-b3f5290ed146?api-version=2014-04-01-Preview'] + cache-control: ['no-store, no-cache'] + content-length: ['80'] + content-type: [application/json; odata=minimalmetadata; streaming=true; charset=utf-8] + dataserviceversion: [3.0;] + date: ['Tue, 21 Mar 2017 16:42:26 GMT'] + location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/operationResults/ad716bef-686e-437e-babc-b3f5290ed146?api-version=2014-04-01-Preview'] + preference-applied: [return-content] + retry-after: ['30'] + server: [Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + x-content-type-options: [nosniff] + x-ms-ratelimit-remaining-subscription-writes: ['1199'] + status: {code: 202, message: Accepted} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db create] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 sqlmanagementclient/0.3.3 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/azureAsyncOperation/ad716bef-686e-437e-babc-b3f5290ed146?api-version=2014-04-01-Preview + response: + body: {string: '{"operationId":"ad716bef-686e-437e-babc-b3f5290ed146","status":"Succeeded","error":null}'} + headers: + azure-asyncoperation: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/azureAsyncOperation/ad716bef-686e-437e-babc-b3f5290ed146?api-version=2014-04-01-Preview'] + cache-control: ['no-store, no-cache'] + content-length: ['88'] + content-type: [application/json; odata=minimalmetadata; streaming=true; charset=utf-8] + dataserviceversion: [3.0;] + date: ['Tue, 21 Mar 2017 16:42:57 GMT'] + server: [Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-content-type-options: [nosniff] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db create] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 sqlmanagementclient/0.3.3 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01?api-version=2014-04-01 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01","name":"cliautomationdb01","type":"Microsoft.Sql/servers/databases","location":"West + US","kind":"v12.0,user","properties":{"databaseId":"c8fe5acb-3081-429b-bf08-f73ee4b9bca4","edition":"Standard","status":"Online","serviceLevelObjective":"S0","collation":"SQL_Latin1_General_CP1_CI_AS","maxSizeBytes":"268435456000","creationDate":"2017-03-21T16:42:29.323Z","currentServiceObjectiveId":"f1173c43-91bd-4aaa-973c-54e79e15235b","requestedServiceObjectiveId":"f1173c43-91bd-4aaa-973c-54e79e15235b","requestedServiceObjectiveName":"S0","sampleName":null,"defaultSecondaryLocation":"East + US","earliestRestoreDate":"2017-03-21T16:52:52.967Z","elasticPoolName":null,"containmentState":2,"readScale":"Disabled","failoverGroupId":null}}'} + headers: + cache-control: ['no-store, no-cache'] + content-length: ['1000'] + content-type: [application/json; odata=minimalmetadata; streaming=true; charset=utf-8] + dataserviceversion: [3.0;] + date: ['Tue, 21 Mar 2017 16:42:58 GMT'] + server: [Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-content-type-options: [nosniff] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db audit-policy show] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 sqlmanagementclient/0.3.3 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/auditingSettings/default?api-version=2015-05-01-preview + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/auditingSettings/Default","name":"Default","type":"Microsoft.Sql/servers/databases/auditingSettings","kind":"","properties":{"state":"Disabled","storageEndpoint":"","storageAccountAccessKey":"","retentionDays":0,"auditActionsAndGroups":[],"storageAccountSubscriptionId":"00000000-0000-0000-0000-000000000000","isStorageSecondaryKeyInUse":false}}'} + headers: + cache-control: [no-cache] + content-length: ['618'] + content-type: [application/json; charset=utf-8] + date: ['Tue, 21 Mar 2017 16:42:59 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db audit-policy update] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 sqlmanagementclient/0.3.3 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/auditingSettings/default?api-version=2015-05-01-preview + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/auditingSettings/Default","name":"Default","type":"Microsoft.Sql/servers/databases/auditingSettings","kind":"","properties":{"state":"Disabled","storageEndpoint":"","storageAccountAccessKey":"","retentionDays":0,"auditActionsAndGroups":[],"storageAccountSubscriptionId":"00000000-0000-0000-0000-000000000000","isStorageSecondaryKeyInUse":false}}'} + headers: + cache-control: [no-cache] + content-length: ['618'] + content-type: [application/json; charset=utf-8] + date: ['Tue, 21 Mar 2017 16:43:01 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: 'b''{"properties": {"retentionDays": 30, "auditActionsAndGroups": ["DATABASE_LOGOUT_GROUP", + "DATABASE_ROLE_MEMBER_CHANGE_GROUP"], "state": "Enabled", "isStorageSecondaryKeyInUse": + false, "storageAccountSubscriptionId": "00000000-0000-0000-0000-000000000000", + "storageAccountAccessKey": "XWb0CfQ1vjVmN2+aU/b1eiKBO1FzJhxkTv2mbp5Ryvucdgv733I+pVm8DeNxt+pxUnN+RrRga97uVCe1xIzc9A==", + "storageEndpoint": "https://clitest000004.blob.core.windows.net/"}}''' + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db audit-policy update] + Connection: [keep-alive] + Content-Length: ['452'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 sqlmanagementclient/0.3.3 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/auditingSettings/default?api-version=2015-05-01-preview + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/auditingSettings/Default","name":"Default","type":"Microsoft.Sql/servers/databases/auditingSettings","kind":"","properties":{"state":"Enabled","storageEndpoint":"https://clitest000004.blob.core.windows.net/","storageAccountAccessKey":"","retentionDays":30,"auditActionsAndGroups":["DATABASE_LOGOUT_GROUP","DATABASE_ROLE_MEMBER_CHANGE_GROUP"],"storageAccountSubscriptionId":"00000000-0000-0000-0000-000000000000","isStorageSecondaryKeyInUse":false}}'} + headers: + cache-control: [no-cache] + content-length: ['732'] + content-type: [application/json; charset=utf-8] + date: ['Tue, 21 Mar 2017 16:43:03 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + x-ms-ratelimit-remaining-subscription-writes: ['1199'] + status: {code: 201, message: Created} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [storage account show] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 storagemanagementclient/0.31.0 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000002/providers/Microsoft.Storage/storageAccounts/clitest000005?api-version=2016-12-01 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000002/providers/Microsoft.Storage/storageAccounts/clitest000005","kind":"Storage","location":"westus","name":"clitest000005","properties":{"creationTime":"2017-03-21T16:42:01.7892993Z","primaryEndpoints":{"blob":"https://clitest000005.blob.core.windows.net/","file":"https://clitest000005.file.core.windows.net/","queue":"https://clitest000005.queue.core.windows.net/","table":"https://clitest000005.table.core.windows.net/"},"primaryLocation":"westus","provisioningState":"Succeeded","statusOfPrimary":"available"},"sku":{"name":"Standard_LRS","tier":"Standard"},"tags":{},"type":"Microsoft.Storage/storageAccounts"} + + '} + headers: + cache-control: [no-cache] + content-length: ['827'] + content-type: [application/json] + date: ['Tue, 21 Mar 2017 16:43:05 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-Azure-Storage-Resource-Provider/1.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db audit-policy update] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 sqlmanagementclient/0.3.3 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/auditingSettings/default?api-version=2015-05-01-preview + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/auditingSettings/Default","name":"Default","type":"Microsoft.Sql/servers/databases/auditingSettings","kind":"","properties":{"state":"Enabled","storageEndpoint":"https://clitest000004.blob.core.windows.net/","storageAccountAccessKey":"","retentionDays":30,"auditActionsAndGroups":["DATABASE_LOGOUT_GROUP","DATABASE_ROLE_MEMBER_CHANGE_GROUP"],"storageAccountSubscriptionId":"00000000-0000-0000-0000-000000000000","isStorageSecondaryKeyInUse":false}}'} + headers: + cache-control: [no-cache] + content-length: ['732'] + content-type: [application/json; charset=utf-8] + date: ['Tue, 21 Mar 2017 16:43:06 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db audit-policy update] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 resourcemanagementclient/0.30.2 Azure-SDK-For-Python + AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resources?api-version=2016-09-01&$filter=name%20eq%20%27clitest000005%27%20and%20%28resourceType%20eq%20%27Microsoft.Storage%2FstorageAccounts%27%20or%20resourceType%20eq%20%27Microsoft.ClassicStorage%2FstorageAccounts%27%29 + response: + body: {string: '{"value":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000002/providers/Microsoft.Storage/storageAccounts/clitest000005","name":"clitest000005","type":"Microsoft.Storage/storageAccounts","sku":{"name":"Standard_LRS","tier":"Standard"},"kind":"Storage","location":"westus","tags":{}}]}'} + headers: + cache-control: [no-cache] + content-length: ['403'] + content-type: [application/json; charset=utf-8] + date: ['Tue, 21 Mar 2017 16:43:06 GMT'] + expires: ['-1'] + pragma: [no-cache] + strict-transport-security: [max-age=31536000; includeSubDomains] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db audit-policy update] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 storagemanagementclient/0.31.0 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000002/providers/Microsoft.Storage/storageAccounts/clitest000005?api-version=2016-12-01 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000002/providers/Microsoft.Storage/storageAccounts/clitest000005","kind":"Storage","location":"westus","name":"clitest000005","properties":{"creationTime":"2017-03-21T16:42:01.7892993Z","primaryEndpoints":{"blob":"https://clitest000005.blob.core.windows.net/","file":"https://clitest000005.file.core.windows.net/","queue":"https://clitest000005.queue.core.windows.net/","table":"https://clitest000005.table.core.windows.net/"},"primaryLocation":"westus","provisioningState":"Succeeded","statusOfPrimary":"available"},"sku":{"name":"Standard_LRS","tier":"Standard"},"tags":{},"type":"Microsoft.Storage/storageAccounts"} + + '} + headers: + cache-control: [no-cache] + content-length: ['827'] + content-type: [application/json] + date: ['Tue, 21 Mar 2017 16:43:07 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-Azure-Storage-Resource-Provider/1.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db audit-policy update] + Connection: [keep-alive] + Content-Length: ['0'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 storagemanagementclient/0.31.0 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: POST + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000002/providers/Microsoft.Storage/storageAccounts/clitest000005/listKeys?api-version=2016-12-01 + response: + body: {string: '{"keys":[{"keyName":"key1","permissions":"Full","value":"/SbYO3wOwqIArNfnJgDxmn4OYSg6UjlaWlw+xQ3/urEwyw/V70oAgeJ+nC4wZ1SmiVmtAOIka6iojA/z1VPl4w=="},{"keyName":"key2","permissions":"Full","value":"l2caComTwlC/ZaIpKTSgxxz7lrsOxIZw9+YqKZiLI/I8zrs8Rca8i66fzXsjnScE7ylCHv0iD4/Yp/jFyGfDYA=="}]} + + '} + headers: + cache-control: [no-cache] + content-length: ['289'] + content-type: [application/json] + date: ['Tue, 21 Mar 2017 16:43:07 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-Azure-Storage-Resource-Provider/1.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-ms-ratelimit-remaining-subscription-writes: ['1198'] + status: {code: 200, message: OK} +- request: + body: 'b''{"properties": {"retentionDays": 30, "auditActionsAndGroups": ["DATABASE_LOGOUT_GROUP", + "DATABASE_ROLE_MEMBER_CHANGE_GROUP"], "state": "Enabled", "isStorageSecondaryKeyInUse": + false, "storageAccountSubscriptionId": "00000000-0000-0000-0000-000000000000", + "storageAccountAccessKey": "/SbYO3wOwqIArNfnJgDxmn4OYSg6UjlaWlw+xQ3/urEwyw/V70oAgeJ+nC4wZ1SmiVmtAOIka6iojA/z1VPl4w==", + "storageEndpoint": "https://clitest000005.blob.core.windows.net/"}}''' + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db audit-policy update] + Connection: [keep-alive] + Content-Length: ['452'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 sqlmanagementclient/0.3.3 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/auditingSettings/default?api-version=2015-05-01-preview + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/auditingSettings/Default","name":"Default","type":"Microsoft.Sql/servers/databases/auditingSettings","kind":"","properties":{"state":"Enabled","storageEndpoint":"https://clitest000005.blob.core.windows.net/","storageAccountAccessKey":"","retentionDays":30,"auditActionsAndGroups":["DATABASE_LOGOUT_GROUP","DATABASE_ROLE_MEMBER_CHANGE_GROUP"],"storageAccountSubscriptionId":"00000000-0000-0000-0000-000000000000","isStorageSecondaryKeyInUse":false}}'} + headers: + cache-control: [no-cache] + content-length: ['732'] + content-type: [application/json; charset=utf-8] + date: ['Tue, 21 Mar 2017 16:43:08 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-ms-ratelimit-remaining-subscription-writes: ['1198'] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db audit-policy update] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 sqlmanagementclient/0.3.3 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/auditingSettings/default?api-version=2015-05-01-preview + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/auditingSettings/Default","name":"Default","type":"Microsoft.Sql/servers/databases/auditingSettings","kind":"","properties":{"state":"Enabled","storageEndpoint":"https://clitest000005.blob.core.windows.net/","storageAccountAccessKey":"","retentionDays":30,"auditActionsAndGroups":["DATABASE_LOGOUT_GROUP","DATABASE_ROLE_MEMBER_CHANGE_GROUP"],"storageAccountSubscriptionId":"00000000-0000-0000-0000-000000000000","isStorageSecondaryKeyInUse":false}}'} + headers: + cache-control: [no-cache] + content-length: ['732'] + content-type: [application/json; charset=utf-8] + date: ['Tue, 21 Mar 2017 16:43:10 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: 'b''{"properties": {"retentionDays": 30, "auditActionsAndGroups": ["DATABASE_LOGOUT_GROUP", + "DATABASE_ROLE_MEMBER_CHANGE_GROUP"], "state": "Disabled", "isStorageSecondaryKeyInUse": + false, "storageAccountSubscriptionId": "00000000-0000-0000-0000-000000000000", + "storageAccountAccessKey": "", "storageEndpoint": "https://clitest000005.blob.core.windows.net/"}}''' + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db audit-policy update] + Connection: [keep-alive] + Content-Length: ['365'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 sqlmanagementclient/0.3.3 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/auditingSettings/default?api-version=2015-05-01-preview + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/auditingSettings/Default","name":"Default","type":"Microsoft.Sql/servers/databases/auditingSettings","kind":"","properties":{"state":"Disabled","storageEndpoint":"https://clitest000005.blob.core.windows.net/","storageAccountAccessKey":"","retentionDays":30,"auditActionsAndGroups":["DATABASE_LOGOUT_GROUP","DATABASE_ROLE_MEMBER_CHANGE_GROUP"],"storageAccountSubscriptionId":"00000000-0000-0000-0000-000000000000","isStorageSecondaryKeyInUse":false}}'} + headers: + cache-control: [no-cache] + content-length: ['733'] + content-type: [application/json; charset=utf-8] + date: ['Tue, 21 Mar 2017 16:43:10 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-ms-ratelimit-remaining-subscription-writes: ['1199'] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db threat-policy show] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 sqlmanagementclient/0.3.3 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/securityAlertPolicies/default?api-version=2014-04-01 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/securityAlertPolicies/default","name":"default","type":"Microsoft.Sql/servers/databases/securityAlertPolicies","location":"West + US","kind":null,"properties":{"useServerDefault":"Enabled","state":"New","disabledAlerts":"Preview","emailAddresses":"","emailAccountAdmins":"Enabled","storageEndpoint":"","storageAccountAccessKey":"","retentionDays":0}}'} + headers: + cache-control: ['no-store, no-cache'] + content-length: ['621'] + content-type: [application/json; odata=minimalmetadata; streaming=true; charset=utf-8] + dataserviceversion: [3.0;] + date: ['Tue, 21 Mar 2017 16:43:12 GMT'] + server: [Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-content-type-options: [nosniff] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db threat-policy update] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 sqlmanagementclient/0.3.3 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/securityAlertPolicies/default?api-version=2014-04-01 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/securityAlertPolicies/default","name":"default","type":"Microsoft.Sql/servers/databases/securityAlertPolicies","location":"West + US","kind":null,"properties":{"useServerDefault":"Enabled","state":"New","disabledAlerts":"Preview","emailAddresses":"","emailAccountAdmins":"Enabled","storageEndpoint":"","storageAccountAccessKey":"","retentionDays":0}}'} + headers: + cache-control: ['no-store, no-cache'] + content-length: ['621'] + content-type: [application/json; odata=minimalmetadata; streaming=true; charset=utf-8] + dataserviceversion: [3.0;] + date: ['Tue, 21 Mar 2017 16:43:14 GMT'] + server: [Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-content-type-options: [nosniff] + status: {code: 200, message: OK} +- request: + body: 'b''{"properties": {"retentionDays": 30, "emailAddresses": "test1@example.com;test2@example.com", + "state": "Enabled", "emailAccountAdmins": "Enabled", "useServerDefault": "Enabled", + "disabledAlerts": "Sql_Injection_Vulnerability;Access_Anomaly", "storageEndpoint": + "https://clitest000004.blob.core.windows.net/", "storageAccountAccessKey": "XWb0CfQ1vjVmN2+aU/b1eiKBO1FzJhxkTv2mbp5Ryvucdgv733I+pVm8DeNxt+pxUnN+RrRga97uVCe1xIzc9A=="}}''' + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db threat-policy update] + Connection: [keep-alive] + Content-Length: ['439'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 sqlmanagementclient/0.3.3 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/securityAlertPolicies/default?api-version=2014-04-01 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/securityAlertPolicies/default","name":"default","type":"Microsoft.Sql/servers/databases/securityAlertPolicies","location":null,"kind":null,"properties":{"useServerDefault":"Enabled","state":"Enabled","disabledAlerts":"Sql_Injection_Vulnerability;Access_Anomaly","emailAddresses":"test1@example.com;test2@example.com","emailAccountAdmins":"Enabled","storageEndpoint":"https://clitest000004.blob.core.windows.net/","storageAccountAccessKey":"XWb0CfQ1vjVmN2+aU/b1eiKBO1FzJhxkTv2mbp5Ryvucdgv733I+pVm8DeNxt+pxUnN+RrRga97uVCe1xIzc9A==","retentionDays":30}}'} + headers: + cache-control: ['no-store, no-cache'] + content-length: ['834'] + content-type: [application/json; odata=minimalmetadata; streaming=true; charset=utf-8] + dataserviceversion: [3.0;] + date: ['Tue, 21 Mar 2017 16:43:16 GMT'] + preference-applied: [return-content] + server: [Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-content-type-options: [nosniff] + x-ms-ratelimit-remaining-subscription-writes: ['1199'] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [storage account keys list] + Connection: [keep-alive] + Content-Length: ['0'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 storagemanagementclient/0.31.0 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: POST + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000002/providers/Microsoft.Storage/storageAccounts/clitest000005/listKeys?api-version=2016-12-01 + response: + body: {string: '{"keys":[{"keyName":"key1","permissions":"Full","value":"/SbYO3wOwqIArNfnJgDxmn4OYSg6UjlaWlw+xQ3/urEwyw/V70oAgeJ+nC4wZ1SmiVmtAOIka6iojA/z1VPl4w=="},{"keyName":"key2","permissions":"Full","value":"l2caComTwlC/ZaIpKTSgxxz7lrsOxIZw9+YqKZiLI/I8zrs8Rca8i66fzXsjnScE7ylCHv0iD4/Yp/jFyGfDYA=="}]} + + '} + headers: + cache-control: [no-cache] + content-length: ['289'] + content-type: [application/json] + date: ['Tue, 21 Mar 2017 16:43:17 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-Azure-Storage-Resource-Provider/1.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-ms-ratelimit-remaining-subscription-writes: ['1198'] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db threat-policy update] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 sqlmanagementclient/0.3.3 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/securityAlertPolicies/default?api-version=2014-04-01 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/securityAlertPolicies/default","name":"default","type":"Microsoft.Sql/servers/databases/securityAlertPolicies","location":"West + US","kind":null,"properties":{"useServerDefault":"Disabled","state":"Enabled","disabledAlerts":"Sql_Injection_Vulnerability;Access_Anomaly","emailAddresses":"test1@example.com;test2@example.com","emailAccountAdmins":"Enabled","storageEndpoint":"https://clitest000004.blob.core.windows.net/","storageAccountAccessKey":"","retentionDays":30}}'} + headers: + cache-control: ['no-store, no-cache'] + content-length: ['752'] + content-type: [application/json; odata=minimalmetadata; streaming=true; charset=utf-8] + dataserviceversion: [3.0;] + date: ['Tue, 21 Mar 2017 16:43:18 GMT'] + server: [Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-content-type-options: [nosniff] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db threat-policy update] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 resourcemanagementclient/0.30.2 Azure-SDK-For-Python + AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resources?api-version=2016-09-01&$filter=name%20eq%20%27clitest000005%27%20and%20%28resourceType%20eq%20%27Microsoft.Storage%2FstorageAccounts%27%20or%20resourceType%20eq%20%27Microsoft.ClassicStorage%2FstorageAccounts%27%29 + response: + body: {string: '{"value":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000002/providers/Microsoft.Storage/storageAccounts/clitest000005","name":"clitest000005","type":"Microsoft.Storage/storageAccounts","sku":{"name":"Standard_LRS","tier":"Standard"},"kind":"Storage","location":"westus","tags":{}}]}'} + headers: + cache-control: [no-cache] + content-length: ['403'] + content-type: [application/json; charset=utf-8] + date: ['Tue, 21 Mar 2017 16:43:19 GMT'] + expires: ['-1'] + pragma: [no-cache] + strict-transport-security: [max-age=31536000; includeSubDomains] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db threat-policy update] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 storagemanagementclient/0.31.0 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000002/providers/Microsoft.Storage/storageAccounts/clitest000005?api-version=2016-12-01 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000002/providers/Microsoft.Storage/storageAccounts/clitest000005","kind":"Storage","location":"westus","name":"clitest000005","properties":{"creationTime":"2017-03-21T16:42:01.7892993Z","primaryEndpoints":{"blob":"https://clitest000005.blob.core.windows.net/","file":"https://clitest000005.file.core.windows.net/","queue":"https://clitest000005.queue.core.windows.net/","table":"https://clitest000005.table.core.windows.net/"},"primaryLocation":"westus","provisioningState":"Succeeded","statusOfPrimary":"available"},"sku":{"name":"Standard_LRS","tier":"Standard"},"tags":{},"type":"Microsoft.Storage/storageAccounts"} + + '} + headers: + cache-control: [no-cache] + content-length: ['827'] + content-type: [application/json] + date: ['Tue, 21 Mar 2017 16:43:19 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-Azure-Storage-Resource-Provider/1.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db threat-policy update] + Connection: [keep-alive] + Content-Length: ['0'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 storagemanagementclient/0.31.0 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: POST + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000002/providers/Microsoft.Storage/storageAccounts/clitest000005/listKeys?api-version=2016-12-01 + response: + body: {string: '{"keys":[{"keyName":"key1","permissions":"Full","value":"/SbYO3wOwqIArNfnJgDxmn4OYSg6UjlaWlw+xQ3/urEwyw/V70oAgeJ+nC4wZ1SmiVmtAOIka6iojA/z1VPl4w=="},{"keyName":"key2","permissions":"Full","value":"l2caComTwlC/ZaIpKTSgxxz7lrsOxIZw9+YqKZiLI/I8zrs8Rca8i66fzXsjnScE7ylCHv0iD4/Yp/jFyGfDYA=="}]} + + '} + headers: + cache-control: [no-cache] + content-length: ['289'] + content-type: [application/json] + date: ['Tue, 21 Mar 2017 16:43:20 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-Azure-Storage-Resource-Provider/1.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-ms-ratelimit-remaining-subscription-writes: ['1198'] + status: {code: 200, message: OK} +- request: + body: 'b''{"properties": {"retentionDays": 30, "emailAddresses": "test1@example.com;test2@example.com", + "state": "Enabled", "emailAccountAdmins": "Enabled", "useServerDefault": "Disabled", + "disabledAlerts": "Sql_Injection_Vulnerability;Access_Anomaly", "storageEndpoint": + "https://clitest000005.blob.core.windows.net/", "storageAccountAccessKey": "/SbYO3wOwqIArNfnJgDxmn4OYSg6UjlaWlw+xQ3/urEwyw/V70oAgeJ+nC4wZ1SmiVmtAOIka6iojA/z1VPl4w=="}}''' + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db threat-policy update] + Connection: [keep-alive] + Content-Length: ['440'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 sqlmanagementclient/0.3.3 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/securityAlertPolicies/default?api-version=2014-04-01 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/securityAlertPolicies/default","name":"default","type":"Microsoft.Sql/servers/databases/securityAlertPolicies","location":null,"kind":null,"properties":{"useServerDefault":"Disabled","state":"Enabled","disabledAlerts":"Sql_Injection_Vulnerability;Access_Anomaly","emailAddresses":"test1@example.com;test2@example.com","emailAccountAdmins":"Enabled","storageEndpoint":"https://clitest000005.blob.core.windows.net/","storageAccountAccessKey":"/SbYO3wOwqIArNfnJgDxmn4OYSg6UjlaWlw+xQ3/urEwyw/V70oAgeJ+nC4wZ1SmiVmtAOIka6iojA/z1VPl4w==","retentionDays":30}}'} + headers: + cache-control: ['no-store, no-cache'] + content-length: ['835'] + content-type: [application/json; odata=minimalmetadata; streaming=true; charset=utf-8] + dataserviceversion: [3.0;] + date: ['Tue, 21 Mar 2017 16:43:21 GMT'] + preference-applied: [return-content] + server: [Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-content-type-options: [nosniff] + x-ms-ratelimit-remaining-subscription-writes: ['1199'] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db audit-policy update] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 sqlmanagementclient/0.3.3 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/auditingSettings/default?api-version=2015-05-01-preview + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/auditingSettings/Default","name":"Default","type":"Microsoft.Sql/servers/databases/auditingSettings","kind":"","properties":{"state":"Disabled","storageEndpoint":"https://clitest000005.blob.core.windows.net/","storageAccountAccessKey":"","retentionDays":30,"auditActionsAndGroups":["DATABASE_LOGOUT_GROUP","DATABASE_ROLE_MEMBER_CHANGE_GROUP"],"storageAccountSubscriptionId":"00000000-0000-0000-0000-000000000000","isStorageSecondaryKeyInUse":false}}'} + headers: + cache-control: [no-cache] + content-length: ['733'] + content-type: [application/json; charset=utf-8] + date: ['Tue, 21 Mar 2017 16:43:22 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: 'b''{"properties": {"retentionDays": 30, "auditActionsAndGroups": ["DATABASE_LOGOUT_GROUP", + "DATABASE_ROLE_MEMBER_CHANGE_GROUP"], "state": "Disabled", "isStorageSecondaryKeyInUse": + false, "storageAccountSubscriptionId": "00000000-0000-0000-0000-000000000000", + "storageAccountAccessKey": "", "storageEndpoint": "https://clitest000005.blob.core.windows.net/"}}''' + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [sql db audit-policy update] + Connection: [keep-alive] + Content-Length: ['365'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 sqlmanagementclient/0.3.3 Azure-SDK-For-Python AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/auditingSettings/default?api-version=2015-05-01-preview + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Sql/servers/clitestserver000003/databases/cliautomationdb01/auditingSettings/Default","name":"Default","type":"Microsoft.Sql/servers/databases/auditingSettings","kind":"","properties":{"state":"Disabled","storageEndpoint":"https://clitest000005.blob.core.windows.net/","storageAccountAccessKey":"","retentionDays":30,"auditActionsAndGroups":["DATABASE_LOGOUT_GROUP","DATABASE_ROLE_MEMBER_CHANGE_GROUP"],"storageAccountSubscriptionId":"00000000-0000-0000-0000-000000000000","isStorageSecondaryKeyInUse":false}}'} + headers: + cache-control: [no-cache] + content-length: ['733'] + content-type: [application/json; charset=utf-8] + date: ['Tue, 21 Mar 2017 16:43:22 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-ms-ratelimit-remaining-subscription-writes: ['1198'] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [group delete] + Connection: [keep-alive] + Content-Length: ['0'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 resourcemanagementclient/0.30.2 Azure-SDK-For-Python + AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: DELETE + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000002?api-version=2016-09-01 + response: + body: {string: ''} + headers: + cache-control: [no-cache] + content-length: ['0'] + date: ['Tue, 21 Mar 2017 16:43:24 GMT'] + expires: ['-1'] + location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/operationresults/eyJqb2JJZCI6IlJFU09VUkNFR1JPVVBERUxFVElPTkpPQi1DTElURVNUOjJFUkcwRjQ3MjQwQ0MxREZBRTM5NzQxQ0I5M0I5QURBNDBDOTk0Q3wyNUI2RDQ5MERCRDUzRTg0LVdFU1RVUyIsImpvYkxvY2F0aW9uIjoid2VzdHVzIn0?api-version=2016-09-01'] + pragma: [no-cache] + retry-after: ['15'] + strict-transport-security: [max-age=31536000; includeSubDomains] + x-ms-ratelimit-remaining-subscription-writes: ['1198'] + status: {code: 202, message: Accepted} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [group delete] + Connection: [keep-alive] + Content-Length: ['0'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.14393-SP0) requests/2.9.1 msrest/0.4.5 + msrest_azure/0.4.7 resourcemanagementclient/0.30.2 Azure-SDK-For-Python + AZURECLI/2.0.1+dev] + accept-language: [en-US] + method: DELETE + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001?api-version=2016-09-01 + response: + body: {string: ''} + headers: + cache-control: [no-cache] + content-length: ['0'] + date: ['Tue, 21 Mar 2017 16:43:26 GMT'] + expires: ['-1'] + location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/operationresults/eyJqb2JJZCI6IlJFU09VUkNFR1JPVVBERUxFVElPTkpPQi1DTElURVNUOjJFUkdGNkEzM0JGQjg5Qzg3NEQ4QkQzMEQ3ODIxMDFDRTJDMzFCN3w4MDY1RTYyNzkyQjMwRTdGLVdFU1RVUyIsImpvYkxvY2F0aW9uIjoid2VzdHVzIn0?api-version=2016-09-01'] + pragma: [no-cache] + retry-after: ['15'] + strict-transport-security: [max-age=31536000; includeSubDomains] + x-ms-ratelimit-remaining-subscription-writes: ['1199'] + status: {code: 202, message: Accepted} +version: 1 diff --git a/src/command_modules/azure-cli-sql/tests/test_sql_commands.py b/src/command_modules/azure-cli-sql/tests/test_sql_commands.py index 63e2472ffbf..1b95e54d843 100644 --- a/src/command_modules/azure-cli-sql/tests/test_sql_commands.py +++ b/src/command_modules/azure-cli-sql/tests/test_sql_commands.py @@ -9,8 +9,8 @@ JMESPathCheck, NoneCheck, ResourceGroupPreparer, - StorageAccountPreparer, - ScenarioTest) + ScenarioTest, + StorageAccountPreparer) from azure.cli.testsdk.preparers import ( AbstractPreparer, SingleValueReplacer) @@ -395,6 +395,146 @@ def test_sql_db_restore(self, resource_group, resource_group_location, server): JMESPathCheck('status', 'Online')]) +class SqlServerDbSecurityScenarioTest(ScenarioTest): + def _get_storage_endpoint(self, storage_account, resource_group): + return self.cmd('storage account show -g {} -n {}' + ' --query primaryEndpoints.blob' + .format(resource_group, storage_account)).get_output_in_json() + + def _get_storage_key(self, storage_account, resource_group): + return self.cmd('storage account keys list -g {} -n {} --query [0].value' + .format(resource_group, storage_account)).get_output_in_json() + + @ResourceGroupPreparer() + @ResourceGroupPreparer(parameter_name='resource_group_2') + @SqlServerPreparer() + @StorageAccountPreparer() + @StorageAccountPreparer(parameter_name='storage_account_2', + resource_group_parameter_name='resource_group_2') + def test_sql_db_security_mgmt(self, resource_group, resource_group_2, + resource_group_location, server, + storage_account, storage_account_2): + database_name = "cliautomationdb01" + + # get storage account endpoint and key + storage_endpoint = self._get_storage_endpoint(storage_account, resource_group) + key = self._get_storage_key(storage_account, resource_group) + + # create db + self.cmd('sql db create -g {} -s {} -n {}' + .format(resource_group, server, database_name), + checks=[ + JMESPathCheck('resourceGroup', resource_group), + JMESPathCheck('name', database_name), + JMESPathCheck('status', 'Online')]) + + # get audit policy + self.cmd('sql db audit-policy show -g {} -s {} -n {}' + .format(resource_group, server, database_name), + checks=[JMESPathCheck('resourceGroup', resource_group)]) + + # update audit policy - enable + state_enabled = 'Enabled' + key + retention_days = 30 + audit_actions_input = 'DATABASE_LOGOUT_GROUP DATABASE_ROLE_MEMBER_CHANGE_GROUP' + audit_actions_expected = ['DATABASE_LOGOUT_GROUP', + 'DATABASE_ROLE_MEMBER_CHANGE_GROUP'] + + self.cmd('sql db audit-policy update -g {} -s {} -n {}' + ' --state {} --storage-key {} --storage-endpoint={}' + ' --retention-days={} --actions {}' + .format(resource_group, server, database_name, state_enabled, key, + storage_endpoint, retention_days, audit_actions_input), + checks=[ + JMESPathCheck('resourceGroup', resource_group), + JMESPathCheck('state', state_enabled), + JMESPathCheck('storageAccountAccessKey', ''), # service doesn't return it + JMESPathCheck('storageEndpoint', storage_endpoint), + JMESPathCheck('retentionDays', retention_days), + JMESPathCheck('auditActionsAndGroups', audit_actions_expected)]) + + # update audit policy - specify storage account and resource group. use secondary key + storage_endpoint_2 = self._get_storage_endpoint(storage_account_2, resource_group_2) + self.cmd('sql db audit-policy update -g {} -s {} -n {} --storage-account {}' + .format(resource_group, server, database_name, storage_account_2, + resource_group_2), + checks=[ + JMESPathCheck('resourceGroup', resource_group), + JMESPathCheck('state', state_enabled), + JMESPathCheck('storageAccountAccessKey', ''), # service doesn't return it + JMESPathCheck('storageEndpoint', storage_endpoint_2), + JMESPathCheck('retentionDays', retention_days), + JMESPathCheck('auditActionsAndGroups', audit_actions_expected)]) + + # update audit policy - disable + state_disabled = 'Disabled' + self.cmd('sql db audit-policy update -g {} -s {} -n {} --state {}' + .format(resource_group, server, database_name, state_disabled), + checks=[ + JMESPathCheck('resourceGroup', resource_group), + JMESPathCheck('state', state_disabled), + JMESPathCheck('storageAccountAccessKey', ''), # service doesn't return it + JMESPathCheck('storageEndpoint', storage_endpoint_2), + JMESPathCheck('retentionDays', retention_days), + JMESPathCheck('auditActionsAndGroups', audit_actions_expected)]) + + # get threat detection policy + self.cmd('sql db threat-policy show -g {} -s {} -n {}' + .format(resource_group, server, database_name), + checks=[JMESPathCheck('resourceGroup', resource_group)]) + + # update threat detection policy - enable + disabled_alerts_input = 'Sql_Injection_Vulnerability Access_Anomaly' + disabled_alerts_expected = 'Sql_Injection_Vulnerability;Access_Anomaly' + email_addresses_input = 'test1@example.com test2@example.com' + email_addresses_expected = 'test1@example.com;test2@example.com' + email_account_admins = 'Enabled' + + self.cmd('sql db threat-policy update -g {} -s {} -n {}' + ' --state {} --storage-key {} --storage-endpoint {}' + ' --retention-days {} --email-addresses {} --disabled-alerts {}' + ' --email-account-admins {}' + .format(resource_group, server, database_name, state_enabled, key, + storage_endpoint, retention_days, email_addresses_input, + disabled_alerts_input, email_account_admins), + checks=[ + JMESPathCheck('resourceGroup', resource_group), + JMESPathCheck('state', state_enabled), + JMESPathCheck('storageAccountAccessKey', key), + JMESPathCheck('storageEndpoint', storage_endpoint), + JMESPathCheck('retentionDays', retention_days), + JMESPathCheck('emailAddresses', email_addresses_expected), + JMESPathCheck('disabledAlerts', disabled_alerts_expected), + JMESPathCheck('emailAccountAdmins', email_account_admins)]) + + # update threat policy - specify storage account and resource group. use secondary key + key_2 = self._get_storage_key(storage_account_2, resource_group_2) + self.cmd('sql db threat-policy update -g {} -s {} -n {} --storage-account {}' + .format(resource_group, server, database_name, storage_account_2, + resource_group_2), + checks=[ + JMESPathCheck('resourceGroup', resource_group), + JMESPathCheck('state', state_enabled), + JMESPathCheck('storageAccountAccessKey', key_2), + JMESPathCheck('storageEndpoint', storage_endpoint_2), + JMESPathCheck('retentionDays', retention_days), + JMESPathCheck('emailAddresses', email_addresses_expected), + JMESPathCheck('disabledAlerts', disabled_alerts_expected), + JMESPathCheck('emailAccountAdmins', email_account_admins)]) + + # update threat policy - disable + self.cmd('sql db audit-policy update -g {} -s {} -n {} --state {}' + .format(resource_group, server, database_name, state_disabled), + checks=[ + JMESPathCheck('resourceGroup', resource_group), + JMESPathCheck('state', state_disabled), + JMESPathCheck('storageAccountAccessKey', ''), # service doesn't return it + JMESPathCheck('storageEndpoint', storage_endpoint_2), + JMESPathCheck('retentionDays', retention_days), + JMESPathCheck('auditActionsAndGroups', audit_actions_expected)]) + + class SqlServerDwMgmtScenarioTest(ScenarioTest): # pylint: disable=too-many-instance-attributes @ResourceGroupPreparer()