IBM Cloud操作汎用ツール作ってみた

# はじめに
IBM Cloudに対して指定するタイミングで操作をしたい、というケースは決して少なくないように思いますが、それに対して特定のIBM Cloudの操作を指定する時間に実行するような機能はありません。
では、IBM Cloudで操作可能な内容の大部分はAPIが公開されており、目的に合わせたツールを作成すれば、意図したタイミングでやりたいことは実行できるのですが、操作するサービス毎にインターフェースが異なり、何かに特化したツールを作ると、他で使いまわすことができなくなります。

対応策を考えていたのですが、1つ有効な方法として、IBM Cloudを操作可能なコンテナを作成し、実行したい内容を後付け(環境変数)で指示すれば良いと思いつきました。後はCode Engineで定期実行させるだけ。。。
こうすれば、IBM CloudのCLI定期実行環境を利用者で用意しなくて良いですし、コマンドの定期実行くらいならCode Engineでも無課金の範囲で動かせるように思います。

# IBM Cloud操作可能なコンテナを作る
できた。 [Docker Hub](https://hub.docker.com/r/hiroapps/ibmcloud-cli-image)

:::note warn
2024/1/24 1.1.0に更新
インストール対象に `jq` コマンドを追加
:::
```Dockerfile:Dockerfile
FROM alpine:3.19

RUN apk update && \
    apk add --no-cache bash curl jq

RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
RUN chmod +x ./kubectl
RUN mv ./kubectl /usr/local/bin

RUN curl -fsSL https://clis.cloud.ibm.com/install/linux | sh -x
RUN ibmcloud plugin install container-registry && \
    ibmcloud plugin install container-service && \
    ibmcloud plugin install cloud-functions && \
    ibmcloud plugin install cloud-internet-services && \
    ibmcloud plugin install cloud-databases && \
    ibmcloud plugin install key-protect && \
    ibmcloud plugin install doi && \
    ibmcloud plugin install tke && \
    ibmcloud plugin install cloud-object-storage && \
    ibmcloud plugin install event-streams && \
    ibmcloud plugin install power-iaas && \
    ibmcloud plugin install vpc-infrastructure && \
    ibmcloud plugin install schematics && \
    ibmcloud plugin install cloud-dns-services && \
    ibmcloud plugin install dl-cli && \
    ibmcloud plugin install watson && \
    ibmcloud plugin install catalogs-management && \
    ibmcloud plugin install tg-cli && \
    ibmcloud plugin install observe-service && \
    ibmcloud plugin install code-engine && \
    ibmcloud plugin install secrets-manager && \
    ibmcloud plugin install monitoring && \
    ibmcloud plugin install logging && \
    ibmcloud plugin install cloudant && \
    ibmcloud plugin install hpcs-cert-mgr && \
    ibmcloud plugin install analytics-engine-v3 && \
    ibmcloud plugin install cra && \
    ibmcloud plugin install event-notifications && \
    ibmcloud plugin install qiskit-runtime && \
    ibmcloud plugin install hpcs && \
    ibmcloud plugin install cbr && \
    ibmcloud plugin install project && \
    ibmcloud plugin install openpages && \
    ibmcloud plugin install sl && \
    ibmcloud plugin install security-compliance

COPY run.sh /
RUN chmod +x /run.sh

ENTRYPOINT ["/run.sh"]
```

```shell:run.sh
#!/bin/sh

printenv |
grep -e "COMMAND[0-9][0-9]" |
sort |
sed -e "s/\=.*//g" |
while read line
do
  echo "## ${line} ##"
  eval "echo \$ \"\${${line}}\"" | sed -e 's/ibmcloud login.*/ibmcloud login *****/g'
  eval "eval \"\${${line}}\""
  if [ $? -ne 0 ]; then
    echo "[ERROR] ${line} exit status is not 0"
    break ;
  fi
  echo ""
done
```

本来 `ibmcloud plugin install`には便利な `-all` オプションがあるのですが、それを付けるとインストールに失敗するプラグインがあるのと、個別指定してもインストールに失敗するプラグインがあるので、とりあえずインストールできたもので構成しています。

実行内容は環境変数 `COMMAND00`~`COMMAND99`で指定されたコマンドを上から順番に実行していきます。
実行に失敗した場合は、そこでエラーになるのでご注意ください。

実行するShellの内容は元々ワンライナーで記述してたのですが ENTRYPOINTに指定したらエラーになったので、あきらめてShellで外だししました。

:::note warn
実行するコマンドを標準出力に表示するようにしていますが、ログイン時に利用する認証情報は表示しないようにしています。逆に、それ以外のコマンドで認証情報付のコマンドを実行する場合は表示されてしまうのでご注意ください。
```shell
eval "echo \$ \"\${${line}}\"" | sed -e 's/ibmcloud login.*/ibmcloud login *****/g'
```
:::

# 実行環境のバージョン情報
- IBM Cloud CLI
```console
$ ibmcloud version
ibmcloud version 2.22.1+98102c0-2023-12-12T22:23:07+00:00
```
- IBM Cloud CLI Plugins
```console
$ ibmcloud plugin list
Listing installed plug-ins...
Plugin Name                                     Version   Status   Private endpoints supported
analytics-engine-v3[ae-v3]                      2.5.0              false
catalogs-management                             2.3.26             true
cbr                                             1.4.1              true
cloud-databases[cdb]                            0.17.1             false
cloud-dns-services[dns/dns-svcs]                0.7.3              true
cloud-functions[wsk/functions/fn]               1.0.78             false
cloud-internet-services[cis]                    1.15.8             true
cloud-object-storage                            1.8.0              false
cloudant[cl]                                    0.1.4              false
code-engine[ce]                                 1.49.2             true
container-registry[cr]                          1.3.5              true
container-service[kubernetes-service/ks]        1.0.579            false
cra                                             2.1.2              false
dl-cli                                          0.5.8              true
doi                                             0.4.5              false
event-notifications[en]                         1.3.0              false
event-streams[es]                               2.5.0              true
hpcs                                            0.1.0              false
hpcs-cert-mgr                                   1.1.0              false
key-protect[kp]                                 0.9.3              true
logging                                         0.0.8              false
monitoring                                      0.2.16             true
observe-service[ob]                             1.0.82             false
openpages[op]                                   0.0.9              true
power-iaas                                      0.7.0              false
project                                         0.0.30             false
qiskit-runtime                                  0.1.5              false
schematics[sch]                                 1.12.14            true
secrets-manager[sm]                             2.0.3              true
security-compliance[scc]                        0.0.4              false
sl                                              1.5.1              false
tg-cli[tg]                                      0.8.12             true
tke                                             1.4.1              true
vpc-infrastructure[infrastructure-service/is]   9.0.1              true
watson                                          0.0.11             false
```
- kubectl
```console
$ kubectl version
Client Version: v1.29.0
```

# 動かしてみよう

https://qiita.com/katahiro/items/68dd7609844b98925937#code-engine%E3%81%A7%E7%A8%BC%E5%83%8D%E8%A8%AD%E5%AE%9A

上記記事のCode EngineのJob登録を参考にして頂けると良いです。
実行するコンテナは下記になります。
`docker.io/hiroapps/ibmcloud-cli-image:1.1.0`

:::note warn
2024/1/24修正 タグ指定を1.0.0から1.1.0へ更新
:::
コマンド実行するだけなので、リソースサイズは最小にするようにしましょう。

リンク先ではシークレットを作成して環境変数を指定していますが、Jobを作成する際に直接指定しても良いです。(そのほうが後で修正しやすいです)
作成時に指定する場合は、Job作成画面の下部で添付のように指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651598/fae8c5d7-6d44-6c5d-2192-607d71c4a609.png)

今回実行するコマンドは下記になります。このコマンドを環境変数の `COMMAND00` `COMMAND01`, `COMMAND02`, `COMMAND03`にセットします。
0. `ibmcloud config --check-version=false`
1. `ibmcloud login --apikey 認証情報 -r jp-tok`
2. `ibmcloud pi st crn:v1:bluemix:public:power-iaas:xxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxx::`
1. `` ibmcloud pi snapc インスタンスID --name snapshot_`date +%Y%m%d_%H%M%S` --volumes ボリュームID``

:::note warn
2024/2/14追記 `COMMAND00` を追加しました。CLIのバージョンアップが問われるので、それを無視するためです。
:::
これはPowerVSのSnapshotを作成するようにしています。
- PowerVSの操作権限のあるサービスIDのAPI鍵でログイン
- 操作対象のPowerVSのワークスペースを指定
- Snapshot作成コマンドを実行

注意して頂きたいのが3つ目のコマンドで、コマンドの中にバッククォートで囲った部分(`date +%Y%m%d_%H%M%S`)は特にバッククォートをエスケープしなくても動作します。

# 動かしてみた
私のCode Engineの環境はLogDNAと連動しているため、Platformでの標準出力がLogDNA側で確認できます。(いろいろマスキングしているので、実際の出力とは異なります)
```
Jan 19 11:58:11 Code Engine cli-test-job-jobrun-c9vfl-0-0 ## COMMAND01 ##
Jan 19 11:58:11 Code Engine cli-test-job-jobrun-c9vfl-0-0 $ ibmcloud login *****
Jan 19 11:58:11 Code Engine cli-test-job-jobrun-c9vfl-0-0 API endpoint: https://cloud.ibm.com
Jan 19 11:58:11 Code Engine cli-test-job-jobrun-c9vfl-0-0 Authenticating...
Jan 19 11:58:21 Code Engine cli-test-job-jobrun-c9vfl-0-0 OK
Jan 19 11:58:31 Code Engine cli-test-job-jobrun-c9vfl-0-0 Targeted account IBM (アカウントID)
Jan 19 11:58:31 Code Engine cli-test-job-jobrun-c9vfl-0-0 Targeted region jp-tok
Jan 19 11:58:31 Code Engine cli-test-job-jobrun-c9vfl-0-0 API endpoint:      https://cloud.ibm.com
Jan 19 11:58:31 Code Engine cli-test-job-jobrun-c9vfl-0-0 Region:            jp-tok
Jan 19 11:58:31 Code Engine cli-test-job-jobrun-c9vfl-0-0 User:              ServiceId-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (Service ID名)
Jan 19 11:58:31 Code Engine cli-test-job-jobrun-c9vfl-0-0 Account:           IBM (アカウントID)
Jan 19 11:58:31 Code Engine cli-test-job-jobrun-c9vfl-0-0 Resource group:    No resource group targeted, use 'ibmcloud target -g RESOURCE_GROUP'
Jan 19 11:58:31 Code Engine cli-test-job-jobrun-c9vfl-0-0 CF API endpoint:   
Jan 19 11:58:31 Code Engine cli-test-job-jobrun-c9vfl-0-0 Org:               
Jan 19 11:58:31 Code Engine cli-test-job-jobrun-c9vfl-0-0 Space:             
Jan 19 11:58:31 Code Engine cli-test-job-jobrun-c9vfl-0-0 ## COMMAND02 ##
Jan 19 11:58:31 Code Engine cli-test-job-jobrun-c9vfl-0-0 $ ibmcloud pi st crn:v1:bluemix:public:power-iaas:xxxxx:a/アカウントID:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx::
Jan 19 11:58:41 Code Engine cli-test-job-jobrun-c9vfl-0-0 Targeting service crn:v1:bluemix:public:power-iaas:xxxxx:a/アカウントID:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx::...
Jan 19 11:58:41 Code Engine cli-test-job-jobrun-c9vfl-0-0 ## COMMAND03 ##
Jan 19 11:58:41 Code Engine cli-test-job-jobrun-c9vfl-0-0 $ ibmcloud pi snapc インスタンスID --name snapshot_`date +%Y%m%d_%H%M%S` --volumes ボリュームID
Jan 19 11:58:41 Code Engine cli-test-job-jobrun-c9vfl-0-0 Creating snapshot for instance インスタンスID under account IBM as user ...
Jan 19 11:58:51 Code Engine cli-test-job-jobrun-c9vfl-0-0 Snapshot snapshot_20240119_025835 with ID of ボリュームID has started.
Jan 19 11:58:51 Code Engine cli-test-job-jobrun-c9vfl-0-0 OK
```

無事に指定した環境変数のコマンドによってPowerVSのSnapshotが作成できたようです。
定期的に実行する場合は、このJobを[Event Subsccription](https://cloud.ibm.com/docs/codeengine?topic=codeengine-subscribe-cron)の機能を利用して定期実行させると良いです。

# 活用方法
どんなユースケースが想定されるかを考えるとぱっと以下が思いつきます。
- リソースサイズ変更
- メンテナンスコマンド実行
- バックアップの実行
- インスタンスの再起動
- etc

上から順番にコマンド実行していくものなので、`ibmcloud`コマンド以外も実行可能なことを考えると、Shellの知識さえあれば、他にもいろいろできそうです。

ネックがあるとすれば、イメージサイズが大きい。Pluginをインストールしまくってる関係で、`846MB`もあります。個人のDocker Hubに格納していますが、制限に引っかかってPullできないことは否定できないため、使う場合は利用頂く方でコンテナレジストリを用意頂いて格納頂くのが良いかと思います。

# ユースケース記事
https://qiita.com/katahiro/items/c9d5774ed4193edae776

https://qiita.com/katahiro/items/0043b25b0b1090c04054

https://qiita.com/katahiro/items/2cb91ff997c3fe8627ec

https://qiita.com/katahiro/items/edb539aa46f9fd97b4f7

# おわりに
いかがでしたでしょうか？この汎用ツールをうまく使えば、自前で定期実行するShell Script環境を調達しなくても、IBM Cloudの操作を自動実行できそうです。ぜひご活用ください。
今後もこのツールを使ったユースケースの記事を紹介できればと思います。