2

我正在使用 CFN 创建 HA 环境,RDS 似乎是 SQL Server DB 而不是实例的最佳方式。现在我尝试了手动部署,使用 RDS 并.bak使用选项组进行恢复,并通过 IAM 和 EC2 将其与 S3 连接。但是当我对 CFN 自动化做同样的事情时,我面临着一堵墙。有办法吗?

4

1 回答 1

0

我没有这个可以“为你打包”的状态,但这应该会给你一个良好的开端......

public abstract class DatabaseFunctionBase
{
    protected static bool IsTaskComplete(SqlConnection sqlConnection, int task)
    {
        try
        {
            using var command = sqlConnection.CreateCommand();
            command.CommandText = "msdb.dbo.rds_task_status";
            command.CommandType = CommandType.StoredProcedure;
            command.Parameters.Add("task_id", SqlDbType.Int).Value = task;
            using var reader = command.ExecuteReader();
            while (reader.Read())
            {
                if (reader.HasRows)
                {
                    var s = new StringBuilder();

                    for (int i = 0; i < reader.FieldCount; i++)
                    {
                        s.AppendLine($"{i}={reader[i]}");
                    }
                    //LambdaLogger.Log(s.ToString());

                    var status = reader.GetString(5);
                    return status == "SUCCESS";
                }
            }

            return false;

        }
        catch (Exception e)
        {
            //LambdaLogger.Log(e.ToString());
            throw;
        }

    }

    protected int GetTaskId(SqlConnection sqlConnection, string dbName)
    {
        try
        {
            using var command = sqlConnection.CreateCommand();
            command.CommandText = "msdb.dbo.rds_task_status";
            command.CommandType = CommandType.StoredProcedure;
            command.Parameters.Add("db_name", SqlDbType.VarChar).Value = dbName;
            do
            {

                using var reader = command.ExecuteReader();
                while (reader.Read())
                {
                    if (reader.HasRows)
                    {
                        var s = new StringBuilder();

                        for (int i = 0; i < reader.FieldCount; i++)
                        {
                            s.AppendLine($"{i}={reader[i]}");
                        }

                        //LambdaLogger.Log(s.ToString());

                        var status = reader.GetString(5);
                        var id = reader.GetInt32(0);
                        var db = reader.GetString(2);
                        if ((status == "CREATED" || status == "IN_PROGRESS") && db == dbName)
                        {
                            return id;
                        }
                    }
                    Thread.Sleep(TimeSpan.FromSeconds(5));
                }
            } while (true);

            throw new InvalidOperationException();

        }
        catch (Exception e)
        {
            //LambdaLogger.Log(e.ToString());
            throw;
        }
    }

    protected async Task BackupDatabaseAsync(BackupRestoreDatabaseInfo info, ILambdaContext context)
    {
        var sqlConnectionStringBuilder = new Microsoft.Data.SqlClient.SqlConnectionStringBuilder
        {

            DataSource = info.DbServer,
            InitialCatalog = info.DbCatalog,
            UserID = info.DbUserId,
            Password = info.DbPassword,
            Authentication = SqlAuthenticationMethod.SqlPassword,
            MultipleActiveResultSets = true
        };


        var connectionString = sqlConnectionStringBuilder.ConnectionString;
        //LambdaLogger.Log($"{nameof(this.BackupDatabaseFunctionAsync)}:{nameof(connectionString)}:{connectionString}");
        await using var sqlConnection = new SqlConnection(connectionString);
        sqlConnection.Open();
        await using var command = sqlConnection.CreateCommand();
        command.CommandText = "msdb.dbo.rds_backup_database";
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.Add("source_db_name", SqlDbType.VarChar).Value = info.DbCatalog.ToString();
        command.Parameters.Add("s3_arn_to_backup_to", SqlDbType.VarChar).Value =
            $"{info.BackupBucket}/{info.DbCatalog}{DateTime.Now:O}.bak";
        command.Parameters.Add("overwrite_S3_backup_file", SqlDbType.TinyInt).Value = 1;
        command.ExecuteNonQuery();

        var taskId = this.GetTaskId(sqlConnection, info.DbCatalog);
        //LambdaLogger.Log($"{nameof(taskId)}={taskId}");

        do
        {
            if (IsTaskComplete(sqlConnection, taskId))
            {
                //LambdaLogger.Log("Complete");
                break;
            }
            //LambdaLogger.Log("Sleeping...");
            await Task.Delay(TimeSpan.FromSeconds(15));
        } while (true);




    }

    protected async Task CreateDatabaseAsync(BackupRestoreDatabaseInfo info, ILambdaContext context)
    {
        var sqlConnectionStringBuilder = new Microsoft.Data.SqlClient.SqlConnectionStringBuilder
        {
            DataSource = info.DbServer,
            UserID = info.DbUserId,
            Password = info.DbPassword,
            Authentication = SqlAuthenticationMethod.SqlPassword,
            MultipleActiveResultSets = true,
            InitialCatalog = info.DbCatalog
        };

        await using (var sqlConnection = new SqlConnection(sqlConnectionStringBuilder.ConnectionString))
        {

            try
            {
                sqlConnection.Open();
                // already present - exit
                return;

            }
            catch (Exception e)
            {
                //LambdaLogger.Log(e.ToString());
            }
        }

        // remove the catalog so we can connect to the server directly
        sqlConnectionStringBuilder.InitialCatalog = string.Empty;


        await using (var sqlConnection = new SqlConnection(sqlConnectionStringBuilder.ConnectionString))
        {

            sqlConnection.Open();

            await using var restoreCommand = sqlConnection.CreateCommand();

            restoreCommand.CommandText = "msdb.dbo.rds_restore_database";
            restoreCommand.CommandType = CommandType.StoredProcedure;
            restoreCommand.Parameters.Add("restore_db_name", SqlDbType.VarChar).Value = info.DbCatalog.ToString();
            restoreCommand.Parameters.Add("s3_arn_to_restore_from", SqlDbType.VarChar).Value =
                $"{info.BackupBucket}/{info.FromCatalog}.bak";
            restoreCommand.ExecuteNonQuery();


            var taskId = GetTaskId(sqlConnection, info.DbCatalog);

            do
            {
                if (IsTaskComplete(sqlConnection, taskId))
                {
                    //LambdaLogger.Log("Complete");
                    break;
                }
                //LambdaLogger.Log("Sleeping...");
                await Task.Delay(TimeSpan.FromSeconds(15));
            } while (true);

        }
        // this might be redundant in a merge
        sqlConnectionStringBuilder.InitialCatalog = info.DbCatalog;

        do
        {
            await using var sqlConnection = new SqlConnection(sqlConnectionStringBuilder.ConnectionString);
            try
            {
                sqlConnection.Open();
                break;
            }
            catch (Exception exception)
            {
                //LambdaLogger.Log(exception.ToString());
                await Task.Delay(TimeSpan.FromSeconds(5));
            }
        } while (context.RemainingTime > TimeSpan.FromMinutes(1));

        // this should already be in merged code
        sqlConnectionStringBuilder.InitialCatalog = info.DbCatalog;
        do
        {
            try
            {
                await using var sqlConnection2 = new SqlConnection(sqlConnectionStringBuilder.ConnectionString);
                sqlConnection2.Open();
                break;

            }
            catch (Exception e)
            {
                //LambdaLogger.Log(e.ToString());
                await Task.Delay(TimeSpan.FromSeconds(15));
            }
        } while (context.RemainingTime > TimeSpan.FromMinutes(1));
        // this should already be in merged code
    }

    protected async Task DeleteDatabase(BackupRestoreDatabaseInfo info, ILambdaContext context)
    {
        if (string.Equals(info.DbCatalog.ToString(), "app", StringComparison.InvariantCultureIgnoreCase))
        {
            return;
        }
        var sqlConnectionStringBuilder = new Microsoft.Data.SqlClient.SqlConnectionStringBuilder
        {
            DataSource = info.DbServer,
            UserID = info.DbUserId,
            Password = info.DbPassword,
            Authentication = SqlAuthenticationMethod.SqlPassword,
            MultipleActiveResultSets = true
        };


        var connectionString = sqlConnectionStringBuilder.ConnectionString;
        //LambdaLogger.Log($"{nameof(this.BackupDatabaseFunctionAsync)}:{nameof(connectionString)}:{connectionString}");
        await using var sqlConnection = new SqlConnection(connectionString);
        sqlConnection.Open();

        await using var dropCommand = sqlConnection.CreateCommand();

        dropCommand.CommandText = "msdb.dbo.rds_drop_database";
        dropCommand.CommandType = CommandType.StoredProcedure;
        dropCommand.Parameters.Add("db_name", SqlDbType.VarChar).Value = info.DbCatalog.ToString();
        dropCommand.ExecuteNonQuery();
    }
}
于 2022-02-09T05:19:03.510 回答