OCI CLI で OCI Console の「Limits, Quotas and Usage」相当の情報を取得してみる。

OCIリソースの Limits と Usage のある時点の断面を、ファイル出力して保持しておくという
必要に迫られたので、表題の件について色々検証してみました。彡(ﾟ)(ﾟ)

# 1. 前提条件/検証環境

OCI上に構築した Private Subnet の Compute(Linux) に OCI CLI をインストールして作業します。
OCI CLI は インストール と 設定(oci setup config) が完了した状態を前提とします。

> 検証によく使う Oracle Cloud Infrastructure(OCI) の
> 環境構成(VCN, Seculity List, 各種Gateway, Route Table, Subnet, Compute)まとめ
> https://qiita.com/ora_gonsuke777/items/08e4781af8c4f7e114ff
> 
> (マニュアル) CLIの構成
> https://docs.oracle.com/ja-jp/iaas/Content/API/SDKDocs/cliconfigure.htm

# 2. Service Name の取得(oci limits definition list ...)

Usage を OCI CLI で取得するには、最終的には oci limits resource-availability get というコマンドを使用します。
このコマンドの引数である service-name や limit-name を取得するために、まずは oci limits definition list を実行します。
※コンパートメントの OCID が必要なため、そちらは予め OCIコンソールで確認しておくこと

```shell
oci limits definition list -c ocid1.tenancy.oc1..xxxxxxxxxx --all

{
  "data": [
    {
      "are-quotas-supported": true,
      "description": "Concurrent Appliance Count",
      "is-deprecated": false,
      "is-dynamic": false,
      "is-eligible-for-limit-increase": true,
      "is-resource-availability-supported": false,
      "name": "active-appliance-count",
      "scope-type": "REGION",
      "service-name": "data-transfer" ★ここが必要
    },
    {
      "are-quotas-supported": false,
      "description": "Concurrent Cloud Shell Users",
      "is-deprecated": false,
      "is-dynamic": false,
      "is-eligible-for-limit-increase": true,
      "is-resource-availability-supported": true,
      "name": "active-users",
      "scope-type": "GLOBAL",
      "service-name": "cloud-shell" ★ここが必要
    },
    {
      "are-quotas-supported": true,
      "description": "Always Free Autonomous Database Instance Count",
      "is-deprecated": false,
      "is-dynamic": false,
      "is-eligible-for-limit-increase": true,
      "is-resource-availability-supported": true,
      "name": "adb-free-count",
      "scope-type": "REGION",
      "service-name": "database" ★ここが必要
    },
：
```

# 3. Limit Name と Limits値 の取得(oci limits value list ...)

上記 2. で取得した Service Name で 次は Limit Name と Limits値 を取得します。
AD(FD)リソース(※) と リージョナルリソース で必要な部分が異なるので、それぞれサンプルを載せておきます。
※AD ... Availability Domain のこと、FD ... Fault Domain のこと

* AD(FD)リソースの場合(※下記は service-name に compute を指定)

```shell
oci limits value list -c ocid1.tenancy.oc1..xxxxxxxxxx --service-name compute --all

{
  "data": [
    {
      "availability-domain": "xxxx:PHX-AD-1",  ★ここが必要
      "name": "bm-dense-io1-36-count", ★ここが必要
      "scope-type": "AD", 
      "value": 0 ★ここがLimits値(例外あり)
    },
    {
      "availability-domain": "xxxx:PHX-AD-2", ★ここが必要
      "name": "bm-dense-io1-36-count", ★ここが必要
      "scope-type": "AD",
      "value": 0 ★ここがLimits値(例外あり)
    },
：
```


* リージョナルリソースの場合(※下記は service-name に vcn を指定)

```shell
oci limits value list -c ocid1.tenancy.oc1..xxxxxxxxxx --service-name vcn --all
{
  "data": [
    {
      "availability-domain": null,
      "name": "dhcp-option-count", ★ここが必要
      "scope-type": "REGION",
      "value": 300 ★ここがLimits値(例外あり)
    },
    {
      "availability-domain": null,
      "name": "flow-log-config-count", ★ここが必要
      "scope-type": "GLOBAL",
      "value": 100 ★ここがLimits値(例外あり)
    },
    {
      "availability-domain": null,
      "name": "internet-gateway-count", ★ここが必要
      "scope-type": "REGION",
      "value": 1 ★ここがLimits値(例外あり)
    },
：
```

# 4. Usage の取得(oci limits resource-availability get ...)

上記 2. と 3. で取得した Service Name/Limit Name で次は Usage を取得します。
oci limits resource-availability getコマンドを実行します。

AD(FD)リソース と リージョナルリソース で必須オプションが異なるので、
それぞれサンプルを載せておきます。

* AD(FD)リソースの場合(※下記は service-name に compute、limit-name に standard-e3-core-ad-count を指定)

```shell
oci limits resource-availability get --compartment-id ocid1.tenancy.oc1..xxxxxxxxxx --limit-name standard-e3-core-ad-count --service-name compute --availability-domain xxxx:PHX-AD-1

{
  "data": {
    "available": 600,
    "effective-quota-value": null,
    "fractional-availability": 600.0,
    "fractional-usage": 0.0,
    "used": 0  ★ここがUsage値(例外あり)
  }
}
```

* リージョナルリソースの場合

```shell
oci limits resource-availability get --compartment-id ocid1.tenancy.oc1..xxxxxxxxxx --limit-name vcn-count --service-name vcn

{
  "data": {
    "available": 49,
    "effective-quota-value": null,
    "fractional-availability": 49.0,
    "fractional-usage": 1.0,
    "used": 1  ★ここがUsage値(例外あり)
  }
}
```

# 5. 複数リージョン の Limits と Usage を取得する場合

上記のコマンドの場合は OCI CLI の デフォルトconfig に定義された
リージョンの Limits と Usage が取得されてきます。

複数リージョン の Limits と Usage を取得したい場合は、
各コマンドに --regionオプション を指定します。

下記は oci limits value listコマンド のサンプルとなります。
JSON の availability-domain がデフォルトの Phoenix と異なるのが判ります。

```shell
oci limits value list -c ocid1.tenancy.oc1..xxxxxxxxxx --service-name compute --all --region us-ashburn-1

{
  "data": [
    {
      "availability-domain": "xxxx:US-ASHBURN-AD-1",
      "name": "bm-dense-io1-36-count",
      "scope-type": "AD",
      "value": 0
    },
    {
      "availability-domain": "xxxx:US-ASHBURN-AD-2",
      "name": "bm-dense-io1-36-count",
      "scope-type": "AD",
      "value": 0
    },
：
```

# 6. スクリプト化(OCILimitsAndUsage.sh)

一連のコマンドを手動で実行するのは流石に無理なので、スクリプト化してみますた。

```shell
#!/usr/bin/bash
#####################################################################################
#
# Overview: This shell outputs csv of the Service Limits and Usage in the OCI tenant.
# Pre-requirement1. Have the OCI CLI installed.
# Pre-requirement2. Make OCI CLI ready to run through the path.
# Pre-requirement3. Complete the configuration(oci setup config).
#
# Usage: ./OCILimitsAndUsage.sh $1 $2 $3
# $1 ... OCI CLI configration file full path
# $2 ... Compartment OCID
# $3 ... Tenancy Name
#
# Example: ./OCILimitsAndUsage.sh /home/opc/.oci/config ocid1.tenancy.oc1..xxxxxxxxxxxxxxxxxxxxxxx ayutenant
#
#####################################################################################

# Get Region Name List
function GetRegionNameList() {
  oci iam region-subscription list | jq -r '.data[]|[."region-name"]|@csv' | tr -d '"' > ${REGION_NAME_LIST}
  return 0;
}

# Get Service Name List
function GetServiceNameList() {
  REGION_NAME=$1
  oci limits definition list -c ${COMPARTMENT_OCID} --all --region ${REGION_NAME} | jq -r '.data[]|[."service-name"]|@csv' | sort -u > ${SERVICE_NAME_LIST}
  return 0;
}

# Get Limit Name List
function GetLimitNameList() {
  REGION_NAME=$1
  cat ${SERVICE_NAME_LIST} | while read -r SERVICE_NAME
  do
    SERVICE_NAME2=`echo ${SERVICE_NAME} | tr -d '"'`
    oci limits value list -c ${COMPARTMENT_OCID} --service-name ${SERVICE_NAME2} --all  --region ${REGION_NAME} | jq -r '.data[]|[."availability-domain", ."name", ."value"]|@csv' > ${LIMIT_NAME_LIST_TMP}
    cat ${LIMIT_NAME_LIST_TMP} | sed "s/^,/\"\",/" | sed -e "s/^/${SERVICE_NAME},/" >> ${LIMIT_NAME_LIST}
  done;
  return 0;
}

# Get Limits and Usage
function GetLimitsAndUsage() {
  REGION_NAME=$1
  DATETIME=`date +"%Y%m%d,%H%M%S"`
  cat ${LIMIT_NAME_LIST} | sed "s/,/ /g" | while read -r SERVICE_NAME AD_NAME LIMIT_NAME LIMIT_VALUE
  do
    SERVICE_NAME2=`echo ${SERVICE_NAME} | tr -d '"'`
    AD_NAME2=`echo ${AD_NAME} | tr -d '"'`
    LIMIT_NAME2=`echo ${LIMIT_NAME} | tr -d '"'`
    LIMIT_VALUE2=`echo ${LIMIT_VALUE} | tr -d '"'`
    if [ "${AD_NAME}" = '""' ] ; then
      # echo "AD is empty."
      oci limits resource-availability get --compartment-id ${COMPARTMENT_OCID} --limit-name ${LIMIT_NAME2} --service-name ${SERVICE_NAME2} --region ${REGION_NAME} | jq -r '.data|[."available", ."used"]|@csv' > ${LIMIT_USAGE_TMP}
      cat ${LIMIT_USAGE_TMP} | sed "s/^/${DATETIME},${TENANCY_NAME},${REGION_NAME},${SERVICE_NAME2},${AD_NAME2},${LIMIT_NAME2},${LIMIT_VALUE2},/" >> ${LIMIT_USAGE_CSV}
    else
      # echo "AD is not empty."
      oci limits resource-availability get --compartment-id ${COMPARTMENT_OCID} --limit-name ${LIMIT_NAME2} --service-name ${SERVICE_NAME2} --availability-domain ${AD_NAME2} --region ${REGION_NAME} | jq -r '.data|[."available", ."used"]|@csv' > ${LIMIT_USAGE_TMP}
      cat ${LIMIT_USAGE_TMP} | sed "s/^/${DATETIME},${TENANCY_NAME},${REGION_NAME},${SERVICE_NAME2},${AD_NAME2},${LIMIT_NAME2},${LIMIT_VALUE2},/" >> ${LIMIT_USAGE_CSV}
    fi;
done;
}

# Parameter Check
if [ -z "$1" -o -z "$2" -o -z "$3" ] ; then
  echo "Usage: ./OCILimitsAndUsage.sh \$1 \$2 \$3";
  exit 1;
fi;

# Initialize
export OCI_CLI_RC_FILE=$1
export COMPARTMENT_OCID=$2
export TENANCY_NAME=$3
export REGION_NAME_LIST="${TENANCY_NAME}_region_name_list.csv"
export SERVICE_NAME_LIST="${TENANCY_NAME}_servie_name_list.csv"
export LIMIT_NAME_LIST="${TENANCY_NAME}_limit_name_list.csv"
export LIMIT_NAME_LIST_TMP="${TENANCY_NAME}_limit_name_list_tmp.tmp"
export LIMIT_USAGE_TMP="${TENANCY_NAME}_limit_usage.tmp"

: > ${REGION_NAME_LIST}
: > ${SERVICE_NAME_LIST}
: > ${LIMIT_NAME_LIST}
: > ${LIMIT_NAME_LIST_TMP}
: > ${LIMIT_USAGE_TMP}

# CSV file initialize
export DATETIME2=`date +"%Y%m%d_%H%M%S"`
export LIMIT_USAGE_CSV="${DATETIME2}_${TENANCY_NAME}_limit_usage.csv"
echo "DATE,TIME,TENANCY_NAME,REGION_NAME,SERVICE_NAME,AVAILABILITY_DOMAIN,LIMIT_NAME,LIMITS,AVAILABLE,USED" > ${LIMIT_USAGE_CSV}

# Get Region Name List
GetRegionNameList

# Get Limit and Usage in the All-Region
cat ${REGION_NAME_LIST} | while read -r REGION_NAME
do
  # Initialize
  : > ${SERVICE_NAME_LIST}
  : > ${LIMIT_NAME_LIST}
  : > ${LIMIT_NAME_LIST_TMP}
  : > ${LIMIT_USAGE_TMP}
  # Get Service Name List
  GetServiceNameList ${REGION_NAME}

  # Get Limit Name List
  GetLimitNameList ${REGION_NAME}

  # Get Limits and Usage
  GetLimitsAndUsage ${REGION_NAME}
done;

# Finalize
rm ${REGION_NAME_LIST}
rm ${SERVICE_NAME_LIST}
rm ${LIMIT_NAME_LIST}
rm ${LIMIT_NAME_LIST_TMP}
rm ${LIMIT_USAGE_TMP}

exit 0;
```

前提条件を整えてシェルを以下のように実行します。

```shell
./OCILimitsAndUsage.sh /home/opc/.oci/config ocid1.tenancy.oc1..xxxxxxxxxxxxxxxxxxxxxxx ayutenant
```

以下のような CSVファイルが出力されます。

```shell
cat 20210724_055626_ayutenant_limit_usage.csv

DATE,TIME,TENANCY_NAME,REGION_NAME,SERVICE_NAME,AVAILABILITY_DOMAIN,LIMIT_NAME,LIMITS,AVAILABLE,USED
：
20210724,055749,ayutenant,us-ashburn-1,compute,xxxx:US-ASHBURN-AD-1,standard-e3-core-ad-count,600,600,0
20210724,055749,ayutenant,us-ashburn-1,compute,xxxx:US-ASHBURN-AD-2,standard-e3-core-ad-count,600,600,0
20210724,055749,ayutenant,us-ashburn-1,compute,xxxx:US-ASHBURN-AD-3,standard-e3-core-ad-count,600,600,0
20210724,055749,ayutenant,us-ashburn-1,compute,xxxx:US-ASHBURN-AD-1,standard-e3-core-count-reservable,0,0,0
20210724,055749,ayutenant,us-ashburn-1,compute,xxxx:US-ASHBURN-AD-2,standard-e3-core-count-reservable,0,0,0
20210724,055749,ayutenant,us-ashburn-1,compute,xxxx:US-ASHBURN-AD-3,standard-e3-core-count-reservable,0,0,0
：
```

GitHub にもうｐしときました。彡(ﾟ)(ﾟ)

https://github.com/gonsuke777/OCI/tree/master/OCILimitsAndUsage

# 7. まとめ

事前に想像していたのの10倍位は面倒でしたやね。彡(ﾟ)(ﾟ)

スクリプトもダーティな作りなんですが、JSON を JSON のまま扱える言語で書いた方がスマートなんですかね。
JSON ⇒ JavaScript で扱うためのデータ構造なので、Node.js とかがエエんかしら……？

# 8. 参考ドキュメント

> (OCI CLI Command Reference) Docs >> limits >> definition >> list
> https://docs.oracle.com/en-us/iaas/tools/oci-cli/2.26.3/oci_cli_docs/cmdref/limits/definition/list.html
> 
> (OCI CLI Command Reference) Docs >> limits >> value >> list
> https://docs.oracle.com/en-us/iaas/tools/oci-cli/2.26.3/oci_cli_docs/cmdref/limits/value/list.html
> 
> (OCI CLI Command Reference) Docs >> limits >> resource-availability >> get
> https://docs.oracle.com/en-us/iaas/tools/oci-cli/2.26.3/oci_cli_docs/cmdref/limits/resource-availability/get.html