S3 にある SQLServer のバックアップ (.bak) から RDS へバッチを使ってリストアしてみる

# ０．はじめに

以前、
こちらの対応をし、

* [SQLServer のバックアップをローカルと NAS と S3 に保存するバッチプログラムを作成してみる \- Qiita](https://qiita.com/kusokamayarou/items/cc9a5c98141477acfc7f)

その後、
こちらの対応をし、

* [AWS CloudFormation で RDS \(SQLServer\) インスタンスを作成してみる \- Qiita](https://qiita.com/kusokamayarou/items/acc150c7ebb36a75e7d8)

最後に、
S3 に保存した SQLServer のバックアップ (.bak) から RDS へリストアしてみようと思います。

出来れば、
ジョブで定期実行して、何ちゃってミラーリングしようかと思っています。

# １．まずは、SQL Server Management Studio を使って、RDS へリストア

1. SQL Server Management Studio で RDS へ接続します。以下の項目を設定し、「接続」ボタンを押下。
    * データベースの種類 : 「データベース エンジン」
    * サーバー名 : [RDS インスタンスのエンドポイント],[ポート番号]
        * 例 : xxxxxxxx.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com,1433
    * 認証 : 「SQL Server 認証」
    * ログイン : [ユーザーID]
    * パスワード : [パスワード]
<br><br>
    * ![スクリーンショット 2017-11-10 15.23.41.png](https://qiita-image-store.s3.amazonaws.com/0/161939/c8d7e76c-3b60-1d9e-d146-b715fa6b9104.png)
<br><br>
1. RDS インスタンスの情報が表示されるので、リストアするデータベースが存在するか確認し、存在する場合は削除します。
    * ※ 上書きは出来ない様です。
    * [SQL Server データベースのインポートとエクスポート \- Amazon Relational Database Service](http://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/SQLServer.Procedural.Importing.html) 
<br><br>
1. 「新しいクエリ」から、以下のコマンドをクエリデザイナーにコピペし、「実行」します。
    * ![スクリーンショット 2017-11-10 15.24.42.png](https://qiita-image-store.s3.amazonaws.com/0/161939/9e5aa413-c31e-45cc-3068-1c935102d51f.png)

    ```bat
exec msdb.dbo.rds_restore_database 
        @restore_db_name='[データベース名]', 
        @s3_arn_to_restore_from='arn:aws:s3:::[S3 バケットの .bak ファイルパス]';
    ```

# ２．バッチ (sqlcmd) を使って、RDS へリストア

1. sqlcmd を使える様にしておきます。
    * [sqlcmd を単体でインストールして使用する方法 \- Microsoft SQL Server \- Project Group](https://www.projectgroup.info/tips/SQLServer/MSSQL_00000002.html)
<br><br>
1. 以下のバッチプログラムを実行します。

```bat:MSSQL_RestoreDB_toRDS_fromS3bak.bat
@echo off
setlocal ENABLEDELAYEDEXPANSION

rem # ==========================================================================
rem # S3 の .bak ファイルから RDS(MSSQL) への DB のリストアを行う。
rem # 
rem # ※以下の項目を設定し直すこと!!
rem #   ・Common : 各種設定
rem #   ・AWS : AWS関連情報
rem #   ・DataBase : データベース関連情報
rem # ==========================================================================

pushd %0¥..
cls

rem # --------------------------------------------------------------------------
rem # Set
rem # --------------------------------------------------------------------------

rem # ----------------------------------
rem # Common
rem # ----------------------------------
title %0
set mypath=%‾dp0
set mypath=%mypath:‾0,-1%
set dt=%date:‾-10%
set tm=%time: =0%
set yyyymmdd=%dt:‾0,4%%dt:‾5,2%%dt:‾8,2%%tm:‾0,2%%tm:‾3,2%%tm:‾6,2%
set USR_INPUT_STR=
set logfile=%‾n0.log
set logfilepath=%mypath%¥%logfile%
set tmpfile=%‾n0.tmp
set tmpfilepath=%mypath%¥%tmpfile%

rem # ----------------------------------
rem # AWS
rem # ----------------------------------
set rds_endpoint=[RDSインスタンスのエンドポイント] ※例 : xxxxxxxx.xxxxxxxx.ap-northeast-1.rds.amazonaws.com,1433
set rds_dbuser=[ユーザーID]
set rds_dbpassword=[パスワード]
set s3_arn_to_restore_from=arn:aws:s3:::[S3 バケットの .bak ファイルパス] ※例 : s3-backet/xxxx.bak

rem # ----------------------------------
rem # DataBase
rem # ----------------------------------
set db_cmd_sqlcmd=sqlcmd -S "%rds_endpoint%" -U %rds_dbuser% -P %rds_dbpassword% -W -h -1 -s "	"
set db_name=[データベース名]

rem # --------------------------------------------------------------------------
rem # Program Start
rem # --------------------------------------------------------------------------
echo.
echo.>> "%logfilepath%"
echo ==========================================================================
echo ==========================================================================>> "%logfilepath%"
echo [%DATE% %TIME%] Program Start - Start
echo [%DATE% %TIME%] Program Start - Start>> "%logfilepath%"

echo [%DATE% %TIME%] rds_endpoint : [%rds_endpoint%]
echo [%DATE% %TIME%] rds_endpoint : [%rds_endpoint%]>> "%logfilepath%"
echo [%DATE% %TIME%] s3_arn_to_restore_from : [%s3_arn_to_restore_from%]
echo [%DATE% %TIME%] s3_arn_to_restore_from : [%s3_arn_to_restore_from%]>> "%logfilepath%"
echo [%DATE% %TIME%] db_name : [%db_name%]
echo [%DATE% %TIME%] db_name : [%db_name%]>> "%logfilepath%"

:do_1
rem # ----------------------------------
rem # Database Check Task Status
rem # ----------------------------------
set rtn_db_check_task_status=
set /a i=0
for /f "delims=" %%A in ('%db_cmd_sqlcmd% -Q "EXIT( exec msdb.dbo.rds_task_status @db_name='%db_name%' )"') do (
  set /a i=i+1
  set A=%%A
  rem secho ==!i!==
  rem echo A:!A!
  set /a ii=0
  for /f "usebackq tokens=1,2,3,4,5,6,7,8,9,10 delims=	" %%A in ('!A!') do (
    set /a ii=ii+1
    rem echo --!ii!--
    rem echo task_id : %%A
    rem echo task_type : %%B
    rem echo database_name : %%C
    rem echo complete : %%D
    rem echo duration mins : %%E
    rem echo lifecycle : %%F
    rem echo task_info : %%G
    rem echo last_updated : %%H
    rem echo created_at : %%I
    rem echo overwrite_S3_backup_file : %%J
    if "%%B"=="RESTORE_DB" (
      if "%%F"=="CREATED" (
        set rtn_db_check_task_status=%rtn_db_check_task_status%,%%F
      ) else if "%%F"=="IN_PROGRESS" (
        set rtn_db_check_task_status=%rtn_db_check_task_status%,%%F
      ) else if "%%F"=="CANCEL_REQUESTED" (
        set rtn_db_check_task_status=%rtn_db_check_task_status%,%%F
      )
    )
  )
)
echo [%DATE% %TIME%] Database Check Task Status : [%rtn_db_check_task_status%]
echo [%DATE% %TIME%] Database Check Task Status : [%rtn_db_check_task_status%]>> "%logfilepath%"

:do_2
rem # ----------------------------------
rem # Database Check Exist
rem # ----------------------------------
if not "%rtn_db_check_task_status%"=="" (
  timeout 5 /nobreak >nul
  goto do_1
)
set rtn_db_check_exist=
set /a i=0
for /f "delims=" %%A in ('%db_cmd_sqlcmd% -Q "set nocount on; select count(*) from sysdatabases where name = '%db_name%'"') do (
  set /a i=i+1
  set A=%%A
  rem echo !i!:!A!
  if !i! equ 1 (
    rem set rtn_db_check_exist=!A:/=!
    set rtn_db_check_exist=!A!
  )
)
echo [%DATE% %TIME%] Database Check Exist : [%rtn_db_check_exist%]
echo [%DATE% %TIME%] Database Check Exist : [%rtn_db_check_exist%]>> "%logfilepath%"

:do_3
rem # ----------------------------------
rem # Database Drop
rem # ----------------------------------
if "%rtn_db_check_exist%"=="0" (
  goto do_4
)
set rtn_db_drop=
set /a i=0
for /f "delims=" %%A in ('%db_cmd_sqlcmd% -Q "set nocount on; drop database %db_name%"') do (
  set /a i=i+1
  set A=%%A
  echo !i!:!A!
  echo [%DATE% %TIME%] Database Drop
  echo [%DATE% %TIME%] Database Drop>> "%logfilepath%"
)
timeout 5 /nobreak >nul
goto do_2

:do_4
rem # ----------------------------------
rem # Database Restore
rem # ----------------------------------
set rtn_db_restore_task_id=
set /a i=0
for /f "delims=" %%A in ('%db_cmd_sqlcmd% -Q "EXIT(exec msdb.dbo.rds_restore_database @restore_db_name='%db_name%', @s3_arn_to_restore_from='%s3_arn_to_restore_from%';)"') do (
  set /a i=i+1
  set A=%%A
  rem echo ==!i!==
  rem echo A:!A!
  echo [%DATE% %TIME%] Database Restore : result:[!A!]
  echo [%DATE% %TIME%] Database Restore : result:[!A!]>> "%logfilepath%"
  set /a ii=0
  for /f "usebackq tokens=1,2,3,4,5,6,7,8,9,10 delims=	" %%A in ('!A!') do (
    set /a ii=ii+1
    if !i! equ 1 (
      set rtn_db_restore_task_id=%%A
    )
  )
)
echo [%DATE% %TIME%] Database Restore : task_id:[%rtn_db_restore_task_id%]
echo [%DATE% %TIME%] Database Restore : task_id:[%rtn_db_restore_task_id%]>> "%logfilepath%"

:do_5
rem # ----------------------------------
rem # Database Check Task Status Restore
rem # ----------------------------------
set rtn_db_check_task_status_restore=
set /a i=0
for /f "delims=" %%A in ('%db_cmd_sqlcmd% -Q "EXIT(exec msdb.dbo.rds_task_status @task_id=%rtn_db_restore_task_id%)"') do (
  set /a i=i+1
  set A=%%A
  rem echo ==!i!==
  rem echo A:!A!
  set /a ii=0
  for /f "usebackq tokens=1,2,3,4,5,6,7,8,9,10 delims=	" %%A in ('!A!') do (
    set /a ii=ii+1
    echo [%DATE% %TIME%] %%A %%B %%C %%D %%E %%F %%J
    echo [%DATE% %TIME%] %%A %%B %%C %%D %%E %%F %%J>> "%logfilepath%"
    if "%%F"=="SUCCESS" (
      set rtn_db_check_task_status_restore=%%F
    ) else if "%%F"=="ERROR" (
      set rtn_db_check_task_status_restore=%%F
    ) else if "%%F"=="CANCELLED" (
      set rtn_db_check_task_status_restore=%%F
    )
  )
)
if "%rtn_db_check_task_status_restore%"=="" (
  timeout 5 /nobreak >nul
  goto do_5
)
echo [%DATE% %TIME%] Database Check Task Status Restore : [%rtn_db_check_task_status_restore%]
echo [%DATE% %TIME%] Database Check Task Status Restore : [%rtn_db_check_task_status_restore%]>> "%logfilepath%"

echo.
echo.>> "%logfilepath%"
echo [%DATE% %TIME%] Database Restore - End
echo [%DATE% %TIME%] Database Restore - End>> "%logfilepath%"
echo ==========================================================================
echo ==========================================================================>> "%logfilepath%"
rem # --------------------------------------------------------------------------
rem # Program End
rem # --------------------------------------------------------------------------

:end
rem pause

exit /b
```

# ９９．ハマりポイント

* 単純に bat 作成するのに時間が掛っちゃいました…。
<br><br>
* 参考にさせて頂いたサイトは、こちら。
    * [SQL Server データベースのインポートとエクスポート \- Amazon Relational Database Service](http://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/SQLServer.Procedural.Importing.html)
    * [RDS for SQL Server でネイティブバックアップ/リストアがサポートされたので軽くメモを at SE の雑記](https://blog.engineer-memo.com/2016/07/29/rds-for-sql-server-%e3%81%a7%e3%83%8d%e3%82%a4%e3%83%86%e3%82%a3%e3%83%96%e3%83%90%e3%83%83%e3%82%af%e3%82%a2%e3%83%83%e3%83%97%e3%83%aa%e3%82%b9%e3%83%88%e3%82%a2%e3%81%8c%e3%82%b5%e3%83%9d%e3%83%bc/)
    * [RDS for Microsoft SQL Serverのバックアップ・リストアが簡単にできるようになりました！ ｜ Developers\.IO](https://dev.classmethod.jp/cloud/aws/import-export-mssql-by-s3-bak-file/)
    * [Amazon RDS for SQL Serverへバックアップファイル\(bak\)からDBを復元する方法 \| Startup Plus, Inc\. \| スタートアッププラス](https://www.startup-plus.com/amazon-rds-for-sql-server%E3%81%B8%E3%83%90%E3%83%83%E3%82%AF%E3%82%A2%E3%83%83%E3%83%97%E3%83%95%E3%82%A1%E3%82%A4%E3%83%ABbak%E3%81%8B%E3%82%89db%E3%82%92%E5%BE%A9%E5%85%83%E3%81%99%E3%82%8B/)
    * [SQLServerの移行作業 \- Qiita](https://qiita.com/kt_higa/items/84f57f9e5095214276b3)

# ＸＸ．まとめ

色々と突っ込みどころのあるプログラムかも知れませんが、
その際は、コメント下さい。

よろしくお願いしますします。