#はじめに
以前、IBM Cloud Object Storageを介したファイル転送という記事を書きました。この記事では主にAWS CLIを使ってICOSとファイル送受信をするやり方について記載しました。
IBM Cloudでは、Intel系のサーバー(WindowsやLinux)だけでなくPower System(AIX, IBMi)の仮想サーバー環境も提供しています。
参考: IBM Power Systems Virtual Server
今後IBM Cloud上の仮想サーバーとしてAIXを使用する予定があるのですが、はて、AWS CLIってAIXで使えるのかな?と思ってみてみると、やっぱりAIX版なんてありません。
参考: AWS CLI バージョン 2 のインストール、更新、アンインストール
ということで、AIXでも使えるようになるべく汎用的な方法、つまりREST API(curl)でアクセスする方法について試してみました。
参考:IBM Cloud Object Storage S3 API について
※とはいえ、現時点で自由に使えるIBM Cloud上にAIX環境がある訳では無いので、ローカルのLinux上のbash/kshで動作確認をしています。恐らくそのままAIXでも使えるんじゃなかろうかと...
※後々気づいたのですが、AWS CLIのV2だと専用のインストーラーが提供されているようだったのでAIXで使えないと思っていたのですが、AWS CLI V1はPythonのpipでインストールできるのでAIXでも同様にいけるっぽいです。V1, V2で何が違うか分かりませんが、そっちの方が楽かも。
参考: pip を使用した AWS CLI バージョン 1 のインストールとアンインストール
関連記事
IBM Cloud Object Storageを介したファイル転送
IBM Cloud Object Storageを介したファイル転送 - その2(curl編)
AIX Toolbox for Linux
今回curlでICOSにアクセスすることを考えると、JSONとかXMLをハンドリングしないといけません。この記事で試しているスクリプトでは、curl, jq, xmllintあたりを使用しています。
最近はめっきりAIX使う機会が減ってきており、はて、Linuxで当たり前のように使っているcurlとかjqとか使えるんだっけ?という疑問が湧いてきました。
AIX Toolbox for Linuxというのがあって、ここから入手できるようです(curl, jq, libxml2)。
参考: AIX Toolbox for Linux Applications
そういえばAIX版のRPMパッケージマネージャーみたいなものがあったんでしたね(完全に忘れてた...)。
(一応Linuxのkshでも確認してますが、上のToolboxにはbashもあるのでbash入れちゃうのもありかも。)
curlによるICOSアクセス
さて、ここからが本題です。ICOS自体の作成方法などは前の記事をご参照ください。
ここでは、curlによるファイルの送受信を試してみます。素でcurlコマンドを打つのは面倒なので、簡素化するためのシェル・スクリプトをいくつか作成しています。
基本的には以下の記述に従います。
参考: curlの使用
大まかな流れとしては以下のような感じです。
- 事前にICOSアクセス用の資格情報の設定をしておく(サービス資格情報の設定)
- 上の資格情報のapikeyを元にアクセストークン(IAMトークン)を取得
- アクセストークンを使用してICOSへの各種アクセス操作を行う
アクセストークンの取得
参考: API キーを使用した IBM Cloud IAM トークンの生成
上の例のように、ICOSのサービス資格情報を作成した時にアサインされたapikeyを使用して、アクセストークンを取得することができます。
アクセストークン取得用スクリプト
#!/bin/sh
### Input parameters
if [[ $# -lt 1 ]]
then
echo Error: invalid arguments
echo " Usage: " `basename $0` "<apikey>"
echo " Example: " `basename $0` "SxyXXXXXXXXXXXXXXXXX"
exit 1
fi
apikey=$1
uriAll="https://iam.cloud.ibm.com/identity/token?grant_type=urn:ibm:params:oauth:grant-type:apikey&apikey=${apikey}"
### get AccessToken
result=$(curl -sS -X "POST" "${uriAll}" -H "Content-Type: application/x-www-form-urlencoded" -H "Accept: application/json")
rc=$?
if [[ ${rc} -gt 0 ]]
then
exit 1
fi
#echo result: ${result}
errorCode=$(echo ${result} | jq .errorCode)
if [[ ${errorCode} != "null" ]]
then
echo errorCode: ${errorCode}
errorMessage=$(echo ${result} | jq .errorMessage)
echo errorMesage: ${errorMessage}
exit 1
fi
access_token=$(echo ${result} | jq .access_token)
if [[ ${access_token} != "null" ]]
then
echo ${access_token}
exit 0
else
unset access_token
exit 1
fi
apikeyを第1引数に指定してスクリプト実行すると、標準出力にアクセストークンが返されます。
# ./getAccessToken.sh SxXXXXXXXX
"eyJraWQiOiIy... <中略> .....-S1M6MSXr2sUqFuR7RDnTUkAghMInw"
内部的には、以下のようなcurlコマンドを発行しており、そのうちのaccess_token部分を拾って標準出力に出すようにしています。
# curl -sS -X "POST" "https://iam.cloud.ibm.com/identity/token?grant_type=urn:ibm:params:oauth:grant-type:apikey&apikey=XXXXX" -H "Content-Type: application/x-www-form-urlencoded" -H "Accept: application/json" | jq .
{
"access_token": "eyJraWQiOiIy... <中略> .....-S1M6MSXr2sUqFuR7RDnTUkAghMInw",
"refresh_token": "OKDBFStiLrIu... <中略> .....-HORjedX2A2WSo4u0jsYJy2MrXJOHeYuBw",
"token_type": "Bearer",
"expires_in": 3600,
"expiration": 1602912855,
"refresh_token_expiration": 1605501255,
"scope": "ibm openid"
}
access_tokenとして返される文字列は結構長いです。1239文字ありました。
これ以降のICOSアクセスには、このaccess_tokenを指定することになりますが、このアクセストークンは利用期限があり、3600秒(1時間)で使えなくなります。取得後1時間経過したら再度取得しなおす必要があります。
さて、このアクセストークンを手動でコピペしたりして後続処理を行うのは面倒なので、環境変数にセットできるような仕組みを用意します。ついでに、ICOSアクセス時に必要なエンドポイント、アクセスしたいICOSのインスタンスIDなども合わせて変数化しておくことにします。
まず、env.shというのを作って、そこに事前に必要な情報をセットします。
#!/bin/sh
export icosAccessPoint="s3.jp-tok.cloud-object-storage.appdomain.cloud"
export instanceID="51xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxf6"
export apikey="xxxxxxxxxxxx"
icosAccessPointには、以下で確認したエンドポイントを設定します。
参考: エンドポイント情報の確認
instanceIDとapikeyの値は、サービス資格情報から判断して設定します。
参考: サービス資格情報の設定
次に、env.shとgetAccessToken.shを使ってアクセストークンを環境変数にセットするスクリプトを用意します。
#!/bin/sh
. ./env.sh
access_token=$(./getAccessToken.sh ${apikey})
rc=$?
if [[ ${rc} -gt 0 ]]
then
echo Error!
echo ${access_token}
unset access_token
else
echo "access_token is set!"
export access_token=$(echo ${access_token} | tr -d \" )
fi
これを実行するときは、実行したシェルで環境変数が有効になるように、先頭に「.」ドットを付けて、. ./setToken.sh
というように現行シェル配下でスクリプトを実行するようにしてください。(sourceコマンド使おうと思ったらAIXに無さそうだったので...)
# . ./setToken.sh
access_token is set!
# echo ${access_token}
eyJra ...<中略>... AGg
setToken.sh実行後、echo ${access_token}
でトークンが表示されていればOKです。以降、ICOSアクセスはこの環境変数を使用するので、setToken.shを実行したシェルで後続処理を実行すればよいです。
つまり、env.shに必要な情報をセットし、. ./setToken.sh
を実行すれば、トークンを直接意識しなくても後続のICOSアクセス処理が行えます。
(1時間経過してアクセスできなくなったら、再度setToken.shを実行すればOK)
ICOSアクセス
setToken.shでICOSアクセス用のトークンが取得できたら、各種操作をやってみます。それぞれ簡易的なスクリプトを用意しました。
以下、いずれもsetToken.shでaccess_tokenをセットしたシェル上で実行する前提です。
Bucketリスト取得
Bucketのリストを取得するためのスクリプトです。
#!/bin/sh
uriAll="https://${icosAccessPoint}"
### get Object List
curl -sS -X "GET" ${uriAll} -H "Authorization: bearer ${access_token}" -H "ibm-service-instance-id: ${instanceID}" | xmllint --format -
# ./getBucketList.sh
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ListAllMyBucketsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Owner>
<ID>51xxxf6</ID>
<DisplayName>514xxxf6</DisplayName>
</Owner>
<Buckets>
<Bucket>
<Name>ise-tag-test01</Name>
<CreationDate>2020-04-16T23:42:42.364Z</CreationDate>
</Bucket>
</Buckets>
</ListAllMyBucketsResult>
上の例では"ise-tag-test01"というBucketが1つのみ存在していることが分かります。
結果はXMLで返されますのでちょっと見にくいですが、面倒なのでここの出力の加工はしていません。
Object(File)リスト取得
Bucketを指定して、Bucketに含まれるオブジェクト(File)のリストを表示するスクリプトです。XMLで返されるとここは分かりにくいので簡易的に加工して出しています(ファイル名、更新日時、サイズのみ出力)。
#!/bin/sh
### Input parameters
if [[ $# -lt 1 ]]
then
echo Error: invalid arguments
echo " Usage: " `basename $0` "<bucketName>"
echo " Example: " `basename $0` "bucket01"
exit 1
fi
bucketName=$1
uriAll="https://${icosAccessPoint}/${bucketName}"
### get Object List
#curl -sS -X "GET" ${uriAll} -H "Authorization: bearer ${access_token}" -H "ibm-service-instance-id: ${instanceID}" | xmllint --format -
result=$(curl -sS -X "GET" ${uriAll} -H "Authorization: bearer ${access_token}" -H "ibm-service-instance-id: ${instanceID}")
rc=$?
if [[ ${rc} -gt 0 ]]
then
echo curl error!
exit 1
fi
error=$(echo ${result} | grep "<Error>")
rc=$?
if [[ ${rc} -eq 0 ]]
then
echo access error!
echo ${result} | xmllint --format -
exit 1
fi
echo -e "Key\t\tLastModified\t\t\tSize"
echo -------------------------------------------------------------------
echo ${result} | xmllint --xpath "//*[local-name()='Contents']" - | sed -e "s/<ETag>[^<]*<\/ETag>//g" -e "s/<ID>[^<)]*<\/ID>//g" -e "s/<DisplayName>[^<)]*<\/DisplayName>//g" -e "s/<StorageClass>[^<)]*<\/StorageClass>//g" -e "s/<\/*Owner>//g" -e "s/<Contents>//g" -e "s/<\/Contents>/
\n/g" -e "s/<[^/<]*>//g" -e "s/<\/[^<]*>/\t/g"
# ./getObjectList.sh ise-tag-test01
Key LastModified Size
-------------------------------------------------------------------
shell.tar.z 2020-10-15T07:56:40.602Z 1088
test2.txt 2020-10-16T09:51:55.393Z 5
test3.txt 2020-10-16T11:02:14.680Z 6
上の例だと、ise-tag-test01というbucket内に、3つのファイルがあるのが確認できます。
Fileのアップロード
指定したbucketにファイルをアップロードするためのスクリプトです。bucketの直下に同名でファイルを転送します。アップロード対象のローカルのファイル名は相対パスでも絶対パスでもOKです。
#!/bin/sh
### Input parameters
if [[ $# -lt 2 ]]
then
echo Error: invalid arguments
echo " Usage: " `basename $0` "<bucketName> <fileName>"
echo " Example: " `basename $0` "bucket01 test.txt"
exit 1
fi
bucketName=$1
sourceFileName=$2
targetFileName=$(echo ${sourceFileName} | sed -e "s/.*\///")
uriAll="https://${icosAccessPoint}/${bucketName}/${targetFileName}"
### put file
curl -sS -X "PUT" ${uriAll} -H "Authorization: bearer ${access_token}" -H "ibm-service-instance-id: ${instanceID}" --data-binary @${sourceFileName}
# ./putFile.sh
Error: invalid arguments
Usage: putFile.sh <bucketName> <fileName>
Example: putFile.sh bucket01 test.txt
# ./putFile.sh ise-tag-test01 /root/ICOS/test4.txt
# ./getObjectList.sh ise-tag-test01
Key LastModified Size
-------------------------------------------------------------------
shell.tar.z 2020-10-15T07:56:40.602Z 1088
test2.txt 2020-10-16T09:51:55.393Z 5
test3.txt 2020-10-16T11:02:14.680Z 6
test4.txt 2020-10-17T05:29:01.684Z 6
test4.txtというファイルが転送されたことが分かります。
Bucket直下ではなく特定のディレクトリ配下にアップロードしたい場合は、第1引数のBucket名にise-tag-test01/dir1
というように配置したいディレクトリも指定すればOKです。
Fileのダウンロード
bucket直下にあるファイルをダウンロードするためのスクリプトです。
bucket名、ファイル名、ダウンロード先ディレクトリを指定します。
#!/bin/sh
### Input parameters
if [[ $# -lt 3 ]]
then
echo Error: invalid arguments
echo " Usage: " `basename $0` "<bucketName> <fileName> <outputDirName>"
echo " Example: " `basename $0` "bucket01 test.txt outDir"
exit 1
fi
bucketName=$1
sourceFileName=$2
outputDirName=$3
targetFileName=$(echo ${sourceFileName} | sed -e "s/.*\///")
uriAll="https://${icosAccessPoint}/${bucketName}/${sourceFileName}"
### get file
curl -sS -X "GET" ${uriAll} -H "Authorization: bearer ${access_token}" -H "ibm-service-instance-id: ${instanceID}" > ${outputDirName}/${targetFileName}
# ./getFile.sh
Error: invalid arguments
Usage: getFile.sh <bucketName> <fileName> <outputDirName>
Example: getFile.sh bucket01 test.txt outDir
# ./getFile.sh ise-tag-test01 test4.txt outDir
# ls -la outDir/
合計 12
drwxr-xr-x. 2 root root 23 10月 17 14:32 .
drwxr-xr-x. 3 root root 4096 10月 17 14:28 ..
-rw-r--r--. 1 root root 6 10月 17 14:32 test4.txt
test4.txtファイルがoutDirにダウンロードされたことが分かります。
Bucket直下ではなく特定のディレクトリ配下にあるファイルをダウンロードしたい場合は、第2引数のファイル名にdir1/test4.txt
というようにディレクトリ付で指定すればOKです。
Fileの削除
ICOS上のファイルを削除するためのスクリプトです。
#!/bin/sh
### Input parameters
if [[ $# -lt 2 ]]
then
echo Error: invalid arguments
echo " Usage: " `basename $0` "<bucketName> <fileName>"
echo " Example: " `basename $0` "bucket01 test.txt"
exit 1
fi
bucketName=$1
fileName=$2
uriAll="https://${icosAccessPoint}/${bucketName}/${fileName}"
### download file
curl -sS -X "DELETE" ${uriAll} -H "Authorization: bearer ${access_token}" -H "ibm-service-instance-id: ${instanceID}"
# ./deleteFile.sh
Error: invalid arguments
Usage: deleteFile.sh <bucketName> <fileName>
Example: deleteFile.sh bucket01 test.txt
# ./getObjectList.sh ise-tag-test01
Key LastModified Size
-------------------------------------------------------------------
shell.tar.z 2020-10-15T07:56:40.602Z 1088
test2.txt 2020-10-16T09:51:55.393Z 5
test3.txt 2020-10-16T11:02:14.680Z 6
test4.txt 2020-10-17T05:29:01.684Z 6
# ./deleteFile.sh ise-tag-test01 test4.txt
# ./getObjectList.sh ise-tag-test01
Key LastModified Size
-------------------------------------------------------------------
shell.tar.z 2020-10-15T07:56:40.602Z 1088
test2.txt 2020-10-16T09:51:55.393Z 5
test3.txt 2020-10-16T11:02:14.680Z 6
bucketからtest4.txtというファイルが削除されたことが分かります。
##補足
ファイルのアップロード、ダウンロードについては、テキストファイルとtarで固められたバイナリファイルで確認しています。tarで固められたファイルをICOSにアップロード/ダウンロードし、その後解凍できることを確認しました。
#おわりに
これで、ICOSアクセス用のクライアントを入れなくても最低限のICOSに対するファイル送受信はできるようになると思います(curl, jq, xmllintあたりは必要ですが)。
IBM Cloud上のPower System仮想サーバーを使う場合、sshでのアクセス方法がどうなるのかがよく分かっていませんが、scpでのアクセス速度が制限されているのであれば、サイズの大きなファイル転送はICOS経由の方が早い可能性もあるので、その場合この仕組みが利用できるのではないかと思います。
※ICOS上のディレクトリ作成/削除がイマイチ分からなかった...。とりあえずこれだけあれば足りそうなのと、調べるの面倒だったので一旦ここまで。