def Run(self, args): """Displays configuration and metadata about a Cloud SQL instance. Information such as instance name, IP address, region, the CA certificate and configuration settings will be displayed. Args: args: argparse.Namespace, The arguments that this command was invoked with. Returns: A dict object representing the instance resource if fetching the instance was successful. Raises: HttpException: A http error response was received while executing api request. ResourceNotFoundError: The SQL instance was not found. """ client = api_util.SqlClient(api_util.API_VERSION_DEFAULT) sql_client = client.sql_client sql_messages = client.sql_messages validate.ValidateInstanceName(args.instance) instance_ref = client.resource_parser.Parse( args.instance, params={'project': properties.VALUES.core.project.GetOrFail}, collection='sql.instances') try: instance = sql_client.instances.Get( sql_messages.SqlInstancesGetRequest( project=instance_ref.project, instance=instance_ref.instance)) instance.state = instance_api_util.GetInstanceState(instance) # TODO(b/122660263): Remove when V1 instances are no longer supported. if instance_api_util.IsInstanceV1(instance): instance_command_util.ShowV1DeprecationWarning() return instance except apitools_exceptions.HttpError as error: if error.status_code == six.moves.http_client.FORBIDDEN: raise exceptions.ResourceNotFoundError( 'There was no instance found at {} or you are not authorized to ' 'access it.'.format(instance_ref.RelativeName())) raise calliope_exceptions.HttpException(error)
def RunBaseCreateCommand(args, release_track): """Creates a new Cloud SQL instance. Args: args: argparse.Namespace, The arguments that this command was invoked with. release_track: base.ReleaseTrack, the release track that this was run under. Returns: A dict object representing the operations resource describing the create operation if the create was successful. Raises: HttpException: A http error response was received while executing api request. """ client = common_api_util.SqlClient(common_api_util.API_VERSION_DEFAULT) sql_client = client.sql_client sql_messages = client.sql_messages validate.ValidateInstanceName(args.instance) instance_ref = client.resource_parser.Parse( args.instance, params={'project': properties.VALUES.core.project.GetOrFail}, collection='sql.instances') # Get the region, tier, and database version from the main if these fields # are not specified. # TODO(b/64266672): Remove once API does not require these fields. if args.IsSpecified('main_instance_name'): main_instance_ref = client.resource_parser.Parse( args.main_instance_name, params={'project': properties.VALUES.core.project.GetOrFail}, collection='sql.instances') try: main_instance_resource = sql_client.instances.Get( sql_messages.SqlInstancesGetRequest( project=instance_ref.project, instance=main_instance_ref.instance)) except apitools_exceptions.HttpError as error: # TODO(b/64292220): Remove once API gives helpful error message. log.debug('operation : %s', str(main_instance_ref)) exc = exceptions.HttpException(error) if resource_property.Get( exc.payload.content, resource_lex.ParseKey('error.errors[0].reason'), None) == 'notAuthorized': msg = ( 'You are either not authorized to access the main instance or ' 'it does not exist.') raise exceptions.HttpException(msg) raise if not args.IsSpecified('region'): args.region = main_instance_resource.region if not args.IsSpecified('database_version'): args.database_version = main_instance_resource.databaseVersion if not args.IsSpecified('tier') and main_instance_resource.settings: args.tier = main_instance_resource.settings.tier # Check for CMEK usage; warn the user about replica inheriting the setting. if main_instance_resource.diskEncryptionConfiguration: command_util.ShowCmekWarning('replica', 'the main instance') instance_resource = ( command_util.InstancesV1Beta4.ConstructCreateInstanceFromArgs( sql_messages, args, instance_ref=instance_ref, release_track=release_track)) # TODO(b/122660263): Remove when V1 instances are no longer supported. # V1 instances are deprecated. Prompt to continue if one is being created. if api_util.IsInstanceV1(instance_resource): log.warning( 'First Generation instances will be automatically upgraded ' 'to Second Generation starting March 4th, 2020, and First Generation ' 'will be fully decommissioned on March 25, 2020. We recommend you ' 'create a Second Generation instance.') console_io.PromptContinue(cancel_on_no=True) if args.pricing_plan == 'PACKAGE': console_io.PromptContinue( 'Charges will begin accruing immediately. Really create Cloud ' 'SQL instance?', cancel_on_no=True) operation_ref = None try: result_operation = sql_client.instances.Insert(instance_resource) operation_ref = client.resource_parser.Create( 'sql.operations', operation=result_operation.name, project=instance_ref.project) if args. async: if not args.IsSpecified('format'): args.format = 'default' return sql_client.operations.Get( sql_messages.SqlOperationsGetRequest( project=operation_ref.project, operation=operation_ref.operation)) operations.OperationsV1Beta4.WaitForOperation( sql_client, operation_ref, 'Creating Cloud SQL instance') log.CreatedResource(instance_ref) new_resource = sql_client.instances.Get( sql_messages.SqlInstancesGetRequest( project=instance_ref.project, instance=instance_ref.instance)) return new_resource except apitools_exceptions.HttpError as error: log.debug('operation : %s', str(operation_ref)) exc = exceptions.HttpException(error) if resource_property.Get( exc.payload.content, resource_lex.ParseKey('error.errors[0].reason'), None) == 'errorMaxInstancePerLabel': msg = resource_property.Get(exc.payload.content, resource_lex.ParseKey('error.message'), None) raise exceptions.HttpException(msg) raise
def testBlankTierInstance(self): instance = data.GetV2Instance(self.project, self.instance) instance.settings.tier = None self.assertFalse(instances_util.IsInstanceV1(self.messages, instance))
def testNonV1TierInstance(self): instance = data.GetV2Instance(self.project, self.instance) instance.backendType = None instance.settings.tier = 'db-n1-standard-1' self.assertFalse(instances_util.IsInstanceV1(self.messages, instance))
def testV1TierInstance(self): instance = data.GetV1Instance(self.project, self.instance) instance.backendType = None instance.settings.tier = 'D0' self.assertTrue(instances_util.IsInstanceV1(self.messages, instance))
def testPostgresInstance(self): self.assertFalse( instances_util.IsInstanceV1( self.messages, data.GetPostgresInstance(self.project, self.instance)))
def testV2MySqlInstance(self): self.assertFalse( instances_util.IsInstanceV1( self.messages, data.GetV2Instance(self.project, self.instance)))
def RunBasePatchCommand(args, release_track): """Updates settings of a Cloud SQL instance using the patch api method. Args: args: argparse.Namespace, The arguments that this command was invoked with. release_track: base.ReleaseTrack, the release track that this was run under. Returns: A dict object representing the operations resource describing the patch operation if the patch was successful. Raises: CancelledError: The user chose not to continue. """ if args.diff and not args.IsSpecified('format'): args.format = 'diff(old, new)' client = common_api_util.SqlClient(common_api_util.API_VERSION_DEFAULT) sql_client = client.sql_client sql_messages = client.sql_messages validate.ValidateInstanceName(args.instance) instance_ref = client.resource_parser.Parse( args.instance, params={'project': properties.VALUES.core.project.GetOrFail}, collection='sql.instances') # If --authorized-networks is used, confirm that the user knows the networks # will get overwritten. if args.authorized_networks: api_util.InstancesV1Beta4.PrintAndConfirmAuthorizedNetworksOverwrite() original_instance_resource = sql_client.instances.Get( sql_messages.SqlInstancesGetRequest(project=instance_ref.project, instance=instance_ref.instance)) patch_instance = command_util.InstancesV1Beta4.ConstructPatchInstanceFromArgs( sql_messages, args, original=original_instance_resource, release_track=release_track) patch_instance.project = instance_ref.project patch_instance.name = instance_ref.instance # TODO(b/122660263): Remove when V1 instances are no longer supported. # V1 deprecation notice. if api_util.IsInstanceV1(sql_messages, original_instance_resource): command_util.ShowV1DeprecationWarning() cleared_fields = _GetConfirmedClearedFields(args, patch_instance, original_instance_resource) # beta only if args.maintenance_window_any: cleared_fields.append('settings.maintenanceWindow') with sql_client.IncludeFields(cleared_fields): result_operation = sql_client.instances.Patch( sql_messages.SqlInstancesPatchRequest( databaseInstance=patch_instance, project=instance_ref.project, instance=instance_ref.instance)) operation_ref = client.resource_parser.Create( 'sql.operations', operation=result_operation.name, project=instance_ref.project) if args.async_: return sql_client.operations.Get( sql_messages.SqlOperationsGetRequest( project=operation_ref.project, operation=operation_ref.operation)) operations.OperationsV1Beta4.WaitForOperation( sql_client, operation_ref, 'Patching Cloud SQL instance') log.UpdatedResource(instance_ref) changed_instance_resource = sql_client.instances.Get( sql_messages.SqlInstancesGetRequest(project=instance_ref.project, instance=instance_ref.instance)) return _Result(changed_instance_resource, original_instance_resource)
def RunBaseCreateCommand(args, release_track): """Creates a new Cloud SQL instance. Args: args: argparse.Namespace, The arguments that this command was invoked with. release_track: base.ReleaseTrack, the release track that this was run under. Returns: A dict object representing the operations resource describing the create operation if the create was successful. Raises: HttpException: A http error response was received while executing api request. RequiredArgumentException: A required argument was not supplied by the user, such as omitting --root-password on a SQL Server instance. ArgumentError: An argument supplied by the user was incorrect, such as attempting to create a V1 instance. """ client = common_api_util.SqlClient(common_api_util.API_VERSION_DEFAULT) sql_client = client.sql_client sql_messages = client.sql_messages validate.ValidateInstanceName(args.instance) instance_ref = client.resource_parser.Parse( args.instance, params={'project': properties.VALUES.core.project.GetOrFail}, collection='sql.instances') # Get the region, tier, and database version from the master if these fields # are not specified. # TODO(b/64266672): Remove once API does not require these fields. if args.IsSpecified('master_instance_name'): master_instance_ref = client.resource_parser.Parse( args.master_instance_name, params={'project': properties.VALUES.core.project.GetOrFail}, collection='sql.instances') try: master_instance_resource = sql_client.instances.Get( sql_messages.SqlInstancesGetRequest( project=instance_ref.project, instance=master_instance_ref.instance)) except apitools_exceptions.HttpError as error: # TODO(b/64292220): Remove once API gives helpful error message. log.debug('operation : %s', six.text_type(master_instance_ref)) exc = exceptions.HttpException(error) if resource_property.Get(exc.payload.content, resource_lex.ParseKey('error.errors[0].reason'), None) == 'notAuthorized': msg = ('You are either not authorized to access the master instance or ' 'it does not exist.') raise exceptions.HttpException(msg) raise if not args.IsSpecified('region'): args.region = master_instance_resource.region if not args.IsSpecified('database_version'): args.database_version = master_instance_resource.databaseVersion.name if not args.IsSpecified('tier') and master_instance_resource.settings: args.tier = master_instance_resource.settings.tier # Check for CMEK usage; warn the user about replica inheriting the setting. if master_instance_resource.diskEncryptionConfiguration: command_util.ShowCmekWarning('replica', 'the master instance') # --root-password is required when creating SQL Server instances if args.IsSpecified('database_version') and args.database_version.startswith( 'SQLSERVER') and not args.IsSpecified('root_password'): raise exceptions.RequiredArgumentException( '--root-password', '`--root-password` is required when creating SQL Server instances.') instance_resource = ( command_util.InstancesV1Beta4.ConstructCreateInstanceFromArgs( sql_messages, args, instance_ref=instance_ref, release_track=release_track)) # TODO(b/122660263): Remove when V1 instances are no longer supported. # V1 instances are deprecated. # Note that the exception type is intentionally vague because the user may not # have directly supplied the offending argument. For example, creating a read # replica defaults its tier to that of its master. if api_util.IsInstanceV1(sql_messages, instance_resource): raise sql_exceptions.ArgumentError( 'First Generation instances can no longer be created.') operation_ref = None try: result_operation = sql_client.instances.Insert(instance_resource) operation_ref = client.resource_parser.Create( 'sql.operations', operation=result_operation.name, project=instance_ref.project) if args.async_: if not args.IsSpecified('format'): args.format = 'default' return sql_client.operations.Get( sql_messages.SqlOperationsGetRequest( project=operation_ref.project, operation=operation_ref.operation)) operations.OperationsV1Beta4.WaitForOperation( sql_client, operation_ref, 'Creating Cloud SQL instance', # TODO(b/138403566): Remove the override once we improve creation times. max_wait_seconds=680) log.CreatedResource(instance_ref) new_resource = sql_client.instances.Get( sql_messages.SqlInstancesGetRequest( project=instance_ref.project, instance=instance_ref.instance)) return new_resource except apitools_exceptions.HttpError as error: log.debug('operation : %s', six.text_type(operation_ref)) exc = exceptions.HttpException(error) if resource_property.Get(exc.payload.content, resource_lex.ParseKey('error.errors[0].reason'), None) == 'errorMaxInstancePerLabel': msg = resource_property.Get(exc.payload.content, resource_lex.ParseKey('error.message'), None) raise exceptions.HttpException(msg) raise
def RunBaseCloneCommand(args, release_track): """Clones a Cloud SQL instance. Args: args: argparse.Namespace, The arguments used to invoke this command. release_track: base.ReleaseTrack, the release track that this was run under. Returns: A dict object representing the operations resource describing the clone operation if the clone was successful. Raises: ArgumentError: The arguments are invalid for some reason. """ client = api_util.SqlClient(api_util.API_VERSION_DEFAULT) sql_client = client.sql_client sql_messages = client.sql_messages source_instance_ref, destination_instance_ref = ( _GetInstanceRefsFromArgs(args, client)) request = sql_messages.SqlInstancesCloneRequest( project=source_instance_ref.project, instance=source_instance_ref.instance, instancesCloneRequest=sql_messages.InstancesCloneRequest( cloneContext=sql_messages.CloneContext( kind='sql#cloneContext', destinationInstanceName=destination_instance_ref.instance))) _UpdateRequestFromArgs(request, args, sql_messages, release_track) # Check if source is V1; raise error if so. # Check if source has customer-managed key; show warning if so. try: source_instance_resource = sql_client.instances.Get( sql_messages.SqlInstancesGetRequest( project=source_instance_ref.project, instance=source_instance_ref.instance)) # TODO(b/122660263): Remove when V1 instances are no longer supported. if instance_util.IsInstanceV1(sql_messages, source_instance_resource): raise exceptions.ArgumentError( 'First Generation instances can no longer be created.') if source_instance_resource.diskEncryptionConfiguration: command_util.ShowCmekWarning('clone', 'the source instance') except apitools_exceptions.HttpError: # This is for informational purposes, so don't throw an error if failure. pass result = sql_client.instances.Clone(request) operation_ref = client.resource_parser.Create( 'sql.operations', operation=result.name, project=destination_instance_ref.project) if args.async_: if not args.IsSpecified('format'): args.format = 'default' return sql_client.operations.Get( sql_messages.SqlOperationsGetRequest( project=operation_ref.project, operation=operation_ref.operation)) operations.OperationsV1Beta4.WaitForOperation(sql_client, operation_ref, 'Cloning Cloud SQL instance') log.CreatedResource(destination_instance_ref) rsource = sql_client.instances.Get( sql_messages.SqlInstancesGetRequest( project=destination_instance_ref.project, instance=destination_instance_ref.instance)) rsource.kind = None return rsource