示例#1
0
def RunProxyConnectCommand(args, supports_database=False):
    """Connects to a Cloud SQL instance through the Cloud SQL Proxy.

  Args:
    args: argparse.Namespace, The arguments that this command was invoked with.
    supports_database: Whether or not the `--database` flag needs to be
      accounted for.

  Returns:
    If no exception is raised this method does not return. A new process is
    started and the original one is killed.
  Raises:
    HttpException: An http error response was received while executing api
        request.
    CloudSqlProxyError: Cloud SQL Proxy could not be found.
    SqlClientNotFoundError: A local SQL client could not be found.
    ConnectionError: An error occurred while trying to connect to the instance.
  """
    client = api_util.SqlClient(api_util.API_VERSION_DEFAULT)
    sql_client = client.sql_client
    sql_messages = client.sql_messages

    instance_ref = instances_command_util.GetInstanceRef(args, client)

    instance_info = sql_client.instances.Get(
        sql_messages.SqlInstancesGetRequest(project=instance_ref.project,
                                            instance=instance_ref.instance))

    if not instances_api_util.IsInstanceV2(sql_messages, instance_info):
        # The Cloud SQL Proxy does not support V1 instances.
        return RunConnectCommand(args, supports_database)

    # If the instance is V2, keep going with the proxy.
    exe = files.FindExecutableOnPath('cloud_sql_proxy')
    if not exe:
        raise exceptions.CloudSqlProxyError(
            'Cloud SQL Proxy could not be found in PATH. See '
            'https://cloud.google.com/sql/docs/mysql/sql-proxy#install for '
            'information on installing.')

    # Check for the executable based on the db version.
    db_type = instance_info.databaseVersion.name.split('_')[0]
    exe_name = constants.DB_EXE.get(db_type, 'mysql')
    exe = files.FindExecutableOnPath(exe_name)
    if not exe:
        raise exceptions.SqlClientNotFoundError(
            '{0} client not found.  Please install a {1} client and make sure '
            'it is in PATH to be able to connect to the database instance.'.
            format(exe_name.title(), exe_name))

    # Start the Cloud SQL Proxy and wait for it to be ready to accept connections.
    port = six.text_type(args.port)
    proxy_process = instances_api_util.StartCloudSqlProxy(instance_info, port)
    atexit.register(proxy_process.kill)

    # Determine what SQL user to connect with.
    sql_user = constants.DEFAULT_SQL_USER[exe_name]
    if args.user:
        sql_user = args.user

    # We have everything we need, time to party!
    flags = constants.EXE_FLAGS[exe_name]
    sql_args = [exe_name]
    if exe_name == 'mssql-cli':
        # mssql-cli merges hostname and port into a single argument
        hostname = 'tcp:127.0.0.1,{0}'.format(port)
        sql_args.extend([flags['hostname'], hostname])
    else:
        sql_args.extend([flags['hostname'], '127.0.0.1', flags['port'], port])
    sql_args.extend([flags['user'], sql_user])
    if 'password' in flags:
        sql_args.append(flags['password'])

    if supports_database:
        sql_args.extend(instances_command_util.GetDatabaseArgs(args, flags))

    instances_command_util.ConnectToInstance(sql_args, sql_user)
    proxy_process.kill()
示例#2
0
def RunConnectCommand(args, supports_database=False):
    """Connects to a Cloud SQL instance directly.

  Args:
    args: argparse.Namespace, The arguments that this command was invoked with.
    supports_database: Whether or not the `--database` flag needs to be
      accounted for.

  Returns:
    If no exception is raised this method does not return. A new process is
    started and the original one is killed.
  Raises:
    HttpException: An http error response was received while executing api
        request.
    UpdateError: An error occurred while updating an instance.
    SqlClientNotFoundError: A local SQL client could not be found.
    ConnectionError: An error occurred while trying to connect to the instance.
  """
    client = api_util.SqlClient(api_util.API_VERSION_DEFAULT)
    sql_client = client.sql_client
    sql_messages = client.sql_messages

    instance_ref = instances_command_util.GetInstanceRef(args, client)

    acl_name = _AllowlistClientIP(instance_ref, sql_client, sql_messages,
                                  client.resource_parser)

    # Get the client IP that the server sees. Sadly we can only do this by
    # checking the name of the authorized network rule.
    retryer = retry.Retryer(max_retrials=2, exponential_sleep_multiplier=2)
    try:
        instance_info, client_ip = retryer.RetryOnResult(
            _GetClientIP,
            [instance_ref, sql_client, acl_name],
            should_retry_if=lambda x, s: x[1] is None,  # client_ip is None
            sleep_ms=500)
    except retry.RetryException:
        raise exceptions.UpdateError(
            'Could not allowlist client IP. Server did '
            'not reply with the allowlisted IP.')

    # Check for the mysql or psql executable based on the db version.
    db_type = instance_info.databaseVersion.name.split('_')[0]
    exe_name = constants.DB_EXE.get(db_type, 'mysql')
    exe = files.FindExecutableOnPath(exe_name)
    if not exe:
        raise exceptions.SqlClientNotFoundError(
            '{0} client not found.  Please install a {1} client and make sure '
            'it is in PATH to be able to connect to the database instance.'.
            format(exe_name.title(), exe_name))

    # Check the version of IP and decide if we need to add ipv4 support.
    ip_type = network.GetIpVersion(client_ip)
    if ip_type == network.IP_VERSION_4:
        if instance_info.settings.ipConfiguration.ipv4Enabled:
            ip_address = instance_info.ipAddresses[0].ipAddress
        else:
            # TODO(b/36049930): ask user if we should enable ipv4 addressing
            message = (
                'It seems your client does not have ipv6 connectivity and '
                'the database instance does not have an ipv4 address. '
                'Please request an ipv4 address for this database instance.')
            raise exceptions.ConnectionError(message)
    elif ip_type == network.IP_VERSION_6:
        ip_address = instance_info.ipv6Address
    else:
        raise exceptions.ConnectionError('Could not connect to SQL server.')

    # Determine what SQL user to connect with.
    sql_user = constants.DEFAULT_SQL_USER[exe_name]
    if args.user:
        sql_user = args.user

    # We have everything we need, time to party!
    flags = constants.EXE_FLAGS[exe_name]
    sql_args = [exe_name, flags['hostname'], ip_address]
    sql_args.extend([flags['user'], sql_user])
    if 'password' in flags:
        sql_args.append(flags['password'])

    if supports_database:
        sql_args.extend(instances_command_util.GetDatabaseArgs(args, flags))

    instances_command_util.ConnectToInstance(sql_args, sql_user)