[OCI]PL/SQLとDBMS_SCHEDULERを使用して定期的な長期バックアップの取得をAutonomous Database自身に実行させてみた

# はじめに

Autonomous Databaseに新しく「長期バックアップの作成機能」が追加されました。
![スクリーンショット 2023-03-15 15.00.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/08eafea6-5e2d-753c-3573-ab5095446475.png)
Autonomous Databaseの長期バックアップには以下のような特徴があります。
* フル・バックアップ（スタンドアローン・バックアップ）が取得される
* 保持期間を最短3ヶ月から最長10年の間で設定可能
* 手動での1回のみの取得だけでなく、バックアップのスケジューリングが可能（週次、月次、年に1回）
* バックアップからのクローン作成が可能
* バックアップを取得したAutonomous Databaseに対するリストアには使用不可
* 課金体系はExadata Storageと同様、同額（1TB単位で切り上げ、例：100GB利用→課金は1TB分）
* バックアップを取得したAutonomous Databaseが削除されるとバックアップも削除される

そこで今回は、Autonomous Databaseに自身の長期バックアップを取得させるPL/SQLプロシージャを作成してみました。
長期バックアップは週次、月次、年次でのバックアップのスケジューリングが可能ですが、例えば2週に1回長期バックアップを取得したい場合や3ヶ月おきに長期バックアップを取得したいといった場合に、DBMS_SCHEDULERでこちらのプロシージャを自動実行することで、より柔軟なスケジュールでの長期バックアップの取得が可能になるかと思います。

# 1.クレデンシャルの作成
今回はAPIキーを使ったクレデンシャルを作成します。
APIキーを使用したクレデンシャルを作成するには、以下のような形式でDBMS_CLOUD.CREATE_CREDENTIALを実行します。
```sql
BEGIN
   DBMS_CLOUD.CREATE_CREDENTIAL (
       credential_name => 'MY_API_KEY_CRED', -- 作成するクレデンシャルの名前
       user_ocid       => 'ocid1.user.oc1..xxxx', -- ユーザのOCID
       tenancy_ocid    => 'ocid1.tenancy.oc1..axxxx', -- テナンシのOCID
       private_key     => 'MIxxxxxxxxxxxxx7g==', -- ユーザのAPIキーのプライベートキー
       fingerprint     => 'b0:xxxxxxxxxxxxxxxxxxxxxxxxxxx:88'); -- ユーザのAPIキーのフィンガープリント
END;
/
```
SQL*Plusから実行して、クレデンシャルを作成します。
```
SQL> BEGIN
  2  	DBMS_CLOUD.CREATE_CREDENTIAL (
  3  	    credential_name => 'MY_API_KEY_CRED',
  4  	    user_ocid	    => 'ocid1.user.oc1..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
  5  	    tenancy_ocid    => 'ocid1.tenancy.oc1..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
  6  	    private_key     => 'MxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxL
  7  ixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxo
  8  gxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxO
  9  Exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxq
 10  9xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxa
 11  ExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxV
 12  4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxA
 13  UxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxO
 14  8xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxk
 15  RxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxY
 16  Exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxh
 17  Qxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx9
 18  wxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxt
 19  Dxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxg
 20  exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxu
 21  BxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxU
 22  Uxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxo
 23  4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxq
 24  UxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxD
 25  0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx2
 26  mxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxl
 27  Pxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
 28  5xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxE
 29  lxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxS
 30  Txxxxxxxxxxxxxxxxxxxxxxxx=',
 31  	    fingerprint     => 'b0:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:88');
 32  END;
 33  /

PL/SQLプロシージャが正常に完了しました。

SQL>
```
APIキーを使用したクレデンシャル「MY_API_KEY_CRED」が作成できました。

# 2. 長期バックアップを作成するPL/SQLプロシージャの作成
バックアップの保持期間を引数として渡して実行すると、長期バックアップを作成するプロシージャ「create_longterm_backup」を作成します。
こちらのプロシージャは、プロシージャ内で、プロシージャを実行しているAutonomous DatabaseのOCID、リージョンを取得し、Autonomous Databaseのバックアップを作成するAPI「CreateAutonomousDatabaseBackup」をコールして、指定したバックアップ保持期間を持つ長期バックアップを作成します。
```sql
CREATE OR REPLACE PROCEDURE create_longterm_backup (days IN NUMBER)
IS
	 -- 変数の宣言
     adb_ocid	       VARCHAR2(200);
     adb_region        VARCHAR2(20);
     payload	       JSON_OBJECT_T := JSON_OBJECT_T('{}');
     resp	           DBMS_CLOUD_TYPES.resp;
BEGIN
    -- v$pdbsからAutonomous Database自身のOCID、リージョンを取得
    SELECT json_value(cloud_identity, '$.REGION'), LOWER(json_value(cloud_identity, '$.DATABASE_OCID'))
        INTO adb_region, adb_ocid FROM v$pdbs;
    -- リクエスト・ボディにパラメータをセット
    payload.put('autonomousDatabaseId', adb_ocid); -- Autonomous DatabaseのOCIDを指定
    payload.put('isLongTermBackup', 'TRUE'); -- Long-Term Backupを指定
    payload.put('retentionPeriodInDays', days); -- バックアップ保持期間を指定
    -- APIをコールしてLong-Term Backupを作成
    resp := DBMS_CLOUD.SEND_REQUEST(
                -- 使用するクレデンシャルの指定
                credential_name => 'MY_API_KEY_CRED',
                -- Long-Term Backupを作成するAPIのURIの指定
                uri => 'https://database.'||adb_region||'.oraclecloud.com/20160918/autonomousDatabaseBackups',
                -- Long-Term Backupを作成するAPIコールのメソッドの指定
                method => DBMS_CLOUD.METHOD_POST,
                -- Long-Term Backupを作成するAPIコールのリクエスト・ボディの指定
                body => UTL_RAW.cast_to_raw(payload.to_clob)
            );
END;
/
```
SQL*Plusから実行して、プロシージャを作成します。
```sql
SQL> CREATE OR REPLACE PROCEDURE create_longterm_backup (days IN NUMBER)
  2  IS
  3  	 -- 変数の宣言
  4  	     adb_ocid	       VARCHAR2(200);
  5  	     adb_region        VARCHAR2(20);
  6  	     payload	       JSON_OBJECT_T := JSON_OBJECT_T('{}');
  7  	     resp	           DBMS_CLOUD_TYPES.resp;
  8  BEGIN
  9  	 -- v$pdbsからAutonomous Database自身のOCID、リージョンを取得
 10      SELECT json_value(cloud_identity, '$.REGION'), LOWER(json_value(cloud_identity, '$.DATABASE_OCID'))
 11  	     INTO adb_region, adb_ocid FROM v$pdbs;
 12  	 -- リクエスト・ボディにパラメータをセット
 13      payload.put('autonomousDatabaseId', adb_ocid); -- Autonomous DatabaseのOCIDを指定
 14      payload.put('isLongTermBackup', 'TRUE'); -- Long-Term Backupを指定
 15      payload.put('retentionPeriodInDays', days); -- バックアップ保持期間を指定
 16      -- APIをコールしてLong-Term Backupを作成
 17      resp := DBMS_CLOUD.SEND_REQUEST(
 18                  -- 使用するクレデンシャルの指定
 19  	             credential_name => 'MY_API_KEY_CRED',
 20  	             -- Long-Term Backupを作成するAPIのURIの指定
 21  	             uri => 'https://database.'||adb_region||'.oraclecloud.com/20160918/autonomousDatabaseBackups',
 22  		         -- Long-Term Backupを作成するAPIコールのメソッドの指定
 23  	             method => DBMS_CLOUD.METHOD_POST,
 24   	             -- Long-Term Backupを作成するAPIコールのリクエスト・ボディの指定
 25  	             body => UTL_RAW.cast_to_raw(payload.to_clob)
 26  		     );
 27  END;
 28  /

プロシージャが作成されました。

SQL> 
```
バックアップの保持期間を引数として渡して実行すると、長期バックアップを作成するプロシージャ「create_longterm_backup」が作成できました。

# 3. 作成したプロシージャの実行
作成したプロシージャ「create_longterm_backup」に引数（バックアップ保持期間）として300（日）を指定して実行してみます。
```sql
SQL> EXEC create_longterm_backup(300)

PL/SQLプロシージャが正常に完了しました。

SQL> 
```
プロシージャが正常に実行できたので、コンソールでAutonomous Databaseのバックアップのセクションを確認してみます。
![スクリーンショット 2023-03-15 13.13.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/8ca63782-a1c3-e9a7-efa1-c3b168a9334d.png)
保持期間300日の長期バックアップが作成中になりました。

しばらく待つと、バックアップの作成が完了し、バックアップの状態が「アクティブ」になりました。
![スクリーンショット 2023-03-15 13.16.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/4930c3c4-f65e-ef18-e415-e06274a8d1f4.png)

# 4.長期バックアップ取得の自動実行
DBMS_SCHEDULERを使用して、長期バックアップを取得するプロシージャ「」をAutonomous Databaseに自動実行させます。
今回は保持期間3年の長期バックアップを2週間おきに取得するジョブ「CREATE_LONGTERM_BACKUP_JOB」を作成します。
```
SQL> BEGIN
  2    DBMS_SCHEDULER.CREATE_JOB (
  3  	 job_name	     => 'CREATE_LONGTERM_BACKUP_JOB', -- ジョブの名前
  4  	 job_type	     => 'STORED_PROCEDURE', -- ジョブのタイプ
  5  	 job_action	     => 'ADMIN.CREATE_LONGTERM_BACKUP', --実行するプロシージャ名
  6  	 number_of_arguments => 1, -- 引数（パラメータ）の数
  7  	 start_date	     => TO_TIMESTAMP_TZ('2023-03-15 17:00:00 +9:00','YYYY-MM-DD HH24:MI:SS TZH:TZM'),  --初回実行のタイムスタンプ
  8  	 repeat_interval     => 'FREQ=WEEKLY;INTERVAL=2', -- 実行頻度
  9  	 auto_drop	     => FALSE); -- 自動削除するかどうか
 10  END;
 11  /

PL/SQLプロシージャが正常に完了しました。

SQL>
```
ジョブ「CREATE_LONGTERM_BACKUP_JOB」で実行するプロシージャ「CREATE_LONGTERM_BACKUP」に渡すパラメータを設定します。
```
SQL> BEGIN
  2    DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE (
  3  	 job_name	    => 'CREATE_LONGTERM_BACKUP_JOB', -- パラメータをセットするジョブの名前
  4  	 argument_position  => 1, -- パラメータの位置
  5  	 argument_value     => 1095); -- パラメータの値
  6  END;
  7  /

PL/SQLプロシージャが正常に完了しました。

SQL>
```
最後にジョブを有効化します。
```
SQL> EXEC DBMS_SCHEDULER.ENABLE('CREATE_LONGTERM_BACKUP_JOB');

PL/SQLプロシージャが正常に完了しました。

SQL> 
```
ジョブ「CREATE_LONGTERM_BACKUP_JOB」を確認します。
```
SQL> SELECT job_name, enabled, last_start_date, next_run_date                        
  2  FROM user_scheduler_jobs
  3  WHERE job_name = 'CREATE_LONGTERM_BACKUP_JOB';

JOB_NAME
--------------------------------------------------------------------------------
ENABL
-----
LAST_START_DATE
---------------------------------------------------------------------------
NEXT_RUN_DATE
---------------------------------------------------------------------------
CREATE_LONGTERM_BACKUP_JOB
TRUE

23-03-15 17:00:00.000000 +09:00


SQL>
```
ジョブ「CREATE_LONGTERM_BACKUP_JOB」が有効化され、初回実行時刻は日本時間2023/3/15 17:00に設定されていることが確認できました。

ジョブが初回実行時刻になるまで、しばし待ちます。

ジョブの初回実行時刻を過ぎたら、コンソールでバックアップを確認します。
![スクリーンショット 2023-03-15 17.00.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/a00ad18c-ec05-90e0-ba95-9fc98f8f32c0.png)
日本時間2023/3/15 17:00に長期バックアップの取得が開始されました。


ジョブ「CREATE_LONGTERM_BACKUP_JOB」を確認します。
```
SQL> SELECT job_name, enabled, last_start_date, next_run_date                        
  2  FROM user_scheduler_jobs
  3  WHERE job_name = 'CREATE_LONGTERM_BACKUP_JOB';

JOB_NAME		  ENABL
------------------------- -----
LAST_START_DATE
---------------------------------------------------------------------------
NEXT_RUN_DATE
---------------------------------------------------------------------------
CREATE_LONGTERM_BACKUP_JO TRUE
B
23-03-15 17:00:00.114730 +09:00
23-03-29 17:00:00.000000 +09:00


SQL>
```
前回のジョブが2023/3/15 17:00に実行され、次回のジョブ実行日時が2週間後の2023/3/29 17:00にセットされていることが確認できました。

# まとめ
PL/SQL SDKを使用して、定期的な長期バックアップの取得をAutonomous Database自身に実行させることができました。

# 参考資料
・[Create Long-Term Backups on Autonomous Database](https://docs.oracle.com/en/cloud/paas/autonomous-database/adbsa/backup-long-term.html#GUID-BD76E02E-AEB0-4450-A6AB-5C9EB1F4EAD0)
・[DBMS_CLOUD.CREATE_CREDENTIAL](https://docs.oracle.com/cd/F19136_01/arpls/DBMS_CLOUD.html#GUID-742FC365-AA09-48A8-922C-1987795CF36A)
・[DBMS_CLOUD.SEND_REQUEST](https://docs.oracle.com/cd//E83857_01/paas/autonomous-database/adbsa/dbms-cloud-subprograms.html#GUID-B063870D-6C1F-4F33-B354-885B73C81D37)
・[OCI API Reference : CreateAutonomousDatabaseBackup](https://docs.oracle.com/en-us/iaas/api/#/en/database/20160918/AutonomousDatabaseBackup/CreateAutonomousDatabaseBackup)
・[OCI API Reference : CreateAutonomousDatabaseBackupDetails](https://docs.oracle.com/en-us/iaas/api/#/en/database/20160918/datatypes/CreateAutonomousDatabaseBackupDetails)
・[DBMS_SCHEDULER.CREATE_JOB](https://docs.oracle.com/cd/F19136_01/arpls/DBMS_SCHEDULER.html#GUID-7E744D62-13F6-40E9-91F0-1569E6C38BBC)
・[DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE](https://docs.oracle.com/cd/F19136_01/arpls/DBMS_SCHEDULER.html#GUID-8B7CB779-6DE3-414C-999B-B0C82E71A19B)
・[DBMS_SCHEDULER.ENABLE](https://docs.oracle.com/cd/F19136_01/arpls/DBMS_SCHEDULER.html#GUID-33CD9F19-8448-4BA8-AAB3-3B82A670085D)