【问题标题】:Is there a way to restore a SQL Server backup in RDS from S3 by using cloudformation?有没有办法使用 cloudformation 从 S3 恢复 RDS 中的 SQL Server 备份?
【发布时间】:2020-05-04 18:50:45
【问题描述】:

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

【问题讨论】:

    标签: sql-server amazon-s3 amazon-rds restore aws-cloudformation-custom-resource


    【解决方案1】:

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

    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();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-28
      • 2013-03-28
      • 1970-01-01
      • 1970-01-01
      • 2013-03-31
      • 1970-01-01
      相关资源
      最近更新 更多