クラウドのリソース一覧をSQLで取得できるようにする

本記事は[Oracle Cloud Infrastructure Advent Calendar 2023](https://qiita.com/advent-calendar/2023/oci)、および[JPOUG Advent Calendar 2023](https://adventar.org/calendars/8844)の19日目の記事です。

# はじめに
　Autonomous Database(以下ADB)のリストに関してはOCI_AUTONOMOUS_DATABASESというディクショナリ(要事前設定)が提供されていますが、本記事ではオブジェクト・ストレージのバケットの一覧を例として同じことを他のリソースでもできるようにします。なお、OCI_AUTONOMOUS_DATABASESビューを閲覧できるようにするためには以下のQiita記事をご参照ください。

https://qiita.com/ora_gonsuke777/items/a6f83ffd74c5d31e1ad9
 
　ではどのようにするかというと、ADBからのクラウドリソースの一覧はPL/SQLのSDKが提供されており、これで一覧の取得が可能です。そして、これをPL/SQL表関数(出力がテーブルイメージの関数)で表示させることでSELECTを可能にします。

 # 事前準備
　本記事ではOCIのAlways Freeの環境を使用して検証しています。
 
### 1. リソース・プリンシパルと動的グループの作成
　未実施であれば以下の記事に従ってこれらを作成してください。

https://qiita.com/nakaie/items/1ba691114b89b9deccb2

### 2. 動的グループへのポリシーの付与
　未実施であれば1で作成した動的グループにバケットの情報の読み取りのポリシーを付与します。この記事ではテナント全体に付与していますが、付与対象の動詞(manage, useなど)と範囲は実際に情報を必要とする範囲や所属組織のセキュリティ規定などに合わせて設定してください。

![20231204_adb19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125837/d8710c76-e17d-bec0-f12e-ce0e67b32d2b.png)

# PL/SQLアプリケーションの作成
### 1. 型の作成
　表関数を作成するためには表関数で使用するための型(TYPE)とその型のテーブル型の作成が必要です。といっても難しいことはなく、表関数での利用目的であれば以下のようにただの複合型として作成するだけです。型のレイアウト(namespace～defined_tags列)は、このサンプルではSDKのバケット一覧表示関数で出力される情報に合わせています。

```SQL
CREATE OR REPLACE TYPE os_bucket_type IS object(
        namespace varchar2(4000),
        name varchar2(4000),
        compartment_id varchar2(4000),
        created_by varchar2(4000),
        time_created timestamp WITH time zone,
        etag varchar2(4000),
        freeform_tags varchar2(32767),
        defined_tags varchar2(32767)
    );
/
CREATE OR REPLACE TYPE os_bucket_tbl IS TABLE OF os_bucket_type;
/
```

### 2. ファンクションの作成
　検索結果が多い場合の出力の高速化とワークのメモリの節約のために、普通の表関数ではなくパイプライン表関数として作成します。このサンプルではリージョン名と検索対象のコンパートメントを引数にしています。バケット一覧を取得するSDKの関数dbms_cloud_oci_obs_object_storage.list_bucketsは引数として名前空間名、コンパートメントのOCID、リージョン名、クレデンシャル名を必要としていますが、名前空間はdbms_cloud_oci_obs_object_storage.get_namespace関数で取得し、クレデンシャル名は「OCI$RESOURCE_PRINCIPAL」固定のためアプリケーション内で設定しています。結果、リージョン名とコンパートメントのOCIDのみをサンプル関数の引数としています。

```SQL
CREATE OR REPLACE FUNCTION list_buckets(
    region         in varchar2,
    compartment_id in varchar2
    ) return os_bucket_tbl PIPELINED
IS
    credential_name      varchar2(32) := 'OCI$RESOURCE_PRINCIPAL';
    response_namespace   dbms_cloud_oci_obs_object_storage_get_namespace_response_t;
    namespace            varchar2(4000);
    response_bucket      dbms_cloud_oci_obs_object_storage_list_buckets_response_t;
    response_bucket_body dbms_cloud_oci_object_storage_bucket_summary_tbl;
BEGIN
    response_namespace := dbms_cloud_oci_obs_object_storage.get_namespace(
        region => region,
        credential_name => credential_name
        );
    IF response_namespace.status_code <> 200 THEN
        RAISE_APPLICATION_ERROR(-20001, '名前空間取得エラー');
    END IF;
    
    namespace := replace(response_namespace.response_body,'"','');
    response_bucket := dbms_cloud_oci_obs_object_storage.list_buckets(
        namespace,
        compartment_id,
        region => region,
        credential_name => credential_name
        );
    IF response_bucket.status_code <> 200 THEN
        RAISE_APPLICATION_ERROR(-20002, 'バケット情報取得エラー');
    END IF;
    
    response_bucket_body := response_bucket.response_body;
    FOR i IN response_bucket_body.first..response_bucket_body.last LOOP
        PIPE ROW(os_bucket_type(
            response_bucket_body(i).namespace ,
            response_bucket_body(i).name,
            response_bucket_body(i).compartment_id,
            response_bucket_body(i).created_by,
            response_bucket_body(i).time_created,
            response_bucket_body(i).etag,
            response_bucket_body(i).freeform_tags.to_string,
            response_bucket_body(i).defined_tags.to_string
            )
        );
    END LOOP;
    RETURN;
END;
/
```

# 実行サンプル
　SELECT文のFROM句に作成した表関数を記述してください。引数はリージョン名と検索対象のコンパートメントのOCIDです。このSELECT文に対してSELECTリストやWHERE句による絞り込みの追加も、他のテーブルと結合したりUNIONしたり、ビューを作成することも可能です。
```
select * from list_buckets('ap-tokyo-1', 'ocid1.tenancy.oc1..aaaaaaaa.....')
```

![20231204_adb24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125837/9994ab6b-607c-f347-8659-896095c780c3.png)