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