IBM Cloud Object Storage (ICOS) をpythonから操作

ちょっと必要になったのでメモしておきます。

IBM CloudのWebコンソールでICOSの操作は可能で、削除、アップロード、ダウンロードはできるのですが、コピーができません。コピーしたくなった（本当はRenameしたかったですが,コピーと削除でやりました）のでpythonでのやり方を調べました。ついでの流れで削除、アップロード、ダウンロードののやり方も書いてあります。

IBM Cloud Object Storage (ICOS) をpythonから操作するには、ibm_boto3　ライブラリを使用します。
参考: [IBM Cloud Docs/Cloud Object Storage/Using Python](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-python)

ibm_boto3 は IBM COS SDK for Pythonとして作成され、boto3ライブラリのフォークです。HMAC署名（つまりAWS V4認証ヘッダー）に加えて、認証にIBM Cloud IAMを使用可能になっています。

ライブラリ詳細はこちら: [IBM COS SDK for Python Documentation](https://ibm.github.io/ibm-cos-sdk-python/index.html)

尚、使用しているCodeはgithubにnotebookで公開しています:
https://github.com/kyokonishito/icos_python/blob/main/icos_sample.ipynb

#1.準備
操作するICOSの以下の情報を取得しておきます。

-  バケット名
-  [エンドポイント](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-endpoints) 
-  操作するICOSの以下の資格情報(当記事ではエディター以上の権限が必要です)
    -  apikey
    -  resource_instance_id
   
バケットを作成していない場合は要作成です:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/0380e67e-3741-24a4-5267-d411fbf027bc.png)


エンドポイントはこちらから:
必要に応じて回復力やロケーションは変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/2bc7b9a0-a188-6afc-9b67-8058c037f47c.png)

資格情報を作成していない場合は要作成です:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/33fe5df7-917f-be9d-3c17-1943b8d78ab3.png)

apikeyとresource_instance_idはサービス資格情報の鍵名をクリックすると表示される
`apikey`と`resource_instance_id`の値です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/e0bb5918-f15d-9147-9112-158bc22ac6b3.png)

pythonの変数にそのままコピーして入れてしまえば、以下の方法で取得できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294516/95a7d694-db5e-f985-d574-427f41fe7ee5.png)


```python
#credencialsにコピペして入れる
credencials={
  "apikey": "XXXXXXXXXXXXXXXXXXXXXXXXX-",
  "cos_hmac_keys": {
    "access_key_id": "XXXXXXXXXXXXXXXXXXXXXXXXX",
    "secret_access_key": "XXXXXXXXXXXXXXXXXXXXXXXXX12345678"
  },
  "endpoints": "https://control.cloud-object-storage.cloud.ibm.com/v2/endpoints",
  "iam_apikey_description": "Auto-generated for key XXXXXXXXXXXXXXXXXXXXXXXXX12345678",
  "iam_apikey_name": "hdm-db2",
  "iam_role_crn": "crn:v1:bluemix:public:iam::::serviceRole:Writer",
  "iam_serviceid_crn": "crn:v1:bluemix:public:iam-identity::XXXXXXXXXXXXXXXXXXXXXXXXX12345678",
  "resource_instance_id": "crn:v1:bluemix:public:cloud-object-storage:global:XXXXXXXXXXXXXXXXXXXXXXXXX12345678"
}

#apiikeyは`credencials["apikey"]
#resource_instance_idはcredencials["resource_instance_id"]
```
上記のようにcredencialsに代入すれば
apiikeyは`credencials["apikey"]`
resource_instance_idは`credencials["resource_instance_id"]`
で取得できます。


#2. ibm_boto3　ライブラリの導入
pipで以下で導入します。

```shell
pip install ibm-cos-sdk
```
ライブラリはClientを使った操作方法とResourceを使った操作方法があります。

1. Client: COS S3 APIへの低レベルのインターフェイスを提供します。リソースによって提供される抽象化されたメソッドや属性を利用するのではなく、直接HTTPレスポンスを処理することを可能にします。
2. Resource: COSに対してオブジェクト指向のインターフェースを提供します。これにより、クライアントオブジェクトが提供する低レベルの呼び出しよりも高いレベルの抽象化が可能になります。

詳細はboto3ライブラリのフォークなので、`AWS` `S3` `Client` `Resource`あたりでググると説明がたくさんでてきますので、気になる方はググってみてください。

なので、Clientを使用したりResourceを使用したり、ibm-cos-sdkを使ってもいろいろ書き方がありますので、下記の例はその一例と思ってください。

#3. resourceの作成
まずは全てに共通するresouceを作成しておきます。

以下のサンプルでは

- `COS_ENDPOINT`に自分のエンドポイントの文字列
- `COS_API_KEY_ID`にAPIKEYの文字列
- `COS_INSTANCE_CRN` にresource_instance_idの文字列

をセットしてください。
以下のコードは上記コードでcredencialsにサービス資格情報を代入している前提で`credencials["apikey"]`と`credencials["resource_instance_id"]`を使用しています。

参考：　https://ibm.github.io/ibm-cos-sdk-python/reference/services/s3.html#service-resource

```python
import ibm_boto3
from ibm_botocore.client import Config

# Constants for IBM COS values
# 自分のエンドポイントに変更する
COS_ENDPOINT = "https://s3.private.jp-tok.cloud-object-storage.appdomain.cloud"

# APIKEYを入れる 例”W00YixxxxxxxxxxMB-odB-2ySfTrFBIQQWanc--P3byk"
COS_API_KEY_ID = credencials["apikey"] 

# resource_instance_idを入れる 例"crn:v1:bluemix:public:cloud-object-storage:global:a/3bf0d9003xxxxxxxxxx1c3e97696b71c:d6f04d83-6c4f-4a62-a165-696756d63903::"
COS_INSTANCE_CRN =  credencials["resource_instance_id"]  

# Create resource
resource = ibm_boto3.resource("s3",
    ibm_api_key_id=COS_API_KEY_ID,
    ibm_service_instance_id=COS_INSTANCE_CRN,
    config=Config(signature_version="oauth"),
    endpoint_url=COS_ENDPOINT
)
```
これを使用してアップロード、ファイルのコピー、削除、ダウンロードを以下でやっていきます。
以下のコード実施前に上記でresourceの作成をしておいてください。
以下resource作成済(importも実施済み)の前提で書いてあります。
またここでは`python-test-2022`というバケット名を使用していますので、自分の環境に合わせて変更してください。

#4. ファイルのアップロード
ファイルのICOSへのアップロードはIBM Cloud WebコンソールのGUIからもできますが、とりあえずここで使用するファイルをアップロードしてみます。
 [厚生労働省のオープンデータ](https://www.mhlw.go.jp/stf/covid-19/open-data.html) に掲載されている,[新規陽性者数の推移（日別）](https://covid19.mhlw.go.jp/public/opendata/newly_confirmed_cases_daily.csv)を取得し、アップロードします。

以下ダウンロードするコードです（ICOSは関係ないです)

```python
#とりあえテスト用ファイルダウンロード
import urllib
url = "https://covid19.mhlw.go.jp/public/opendata/newly_confirmed_cases_daily.csv"
save_file = "newly_confirmed_cases_daily.csv"
data = urllib.request.urlopen(url).read()
with open(save_file, mode="wb") as f:
    f.write(data)
```

##4-1. アップロードの実施

パラメータ詳細は以下を参照：
- [S3.ServiceResource.Bucket](https://ibm.github.io/ibm-cos-sdk-python/reference/services/s3.html#S3.ServiceResource.Bucket)
- [S3.Bucket.upload_file](https://ibm.github.io/ibm-cos-sdk-python/reference/services/s3.html#S3.Bucket.upload_file)


```python
#アップロード先Bucket名
target_bucket = "python-test-2022" 
#アップロード 元ファイル名
src_file = "newly_confirmed_cases_daily.csv"
#アップロード 先ファイル名(必要ならpathをつける)
target_file ="newly_confirmed_cases_daily.csv"

bucket = resource.Bucket(target_bucket)
bucket.upload_file(src_file, target_file)
```

##4-2. 確認のためアップロードしたファイルのちょっと(先頭1000byte)中身をみる（UTFエンコーディングの文字列ファイルである場合）

```py
#確認
object = resource.Object(target_bucket, target_file)
response = object.get()
body = response['Body'].read(1000)
print(body.decode('utf-8', "ignore"))
```
出力：

```sh
Date,ALL,Hokkaido,Aomori,Iwate,Miyagi,Akita,Yamagata,Fukushima,Ibaraki,Tochigi,Gunma,Saitama,Chiba,Tokyo,Kanagawa,Niigata,Toyama,Ishikawa,Fukui,Yamanashi,Nagano,Gifu,Shizuoka,Aichi,Mie,Shiga,Kyoto,Osaka,Hyogo,Nara,Wakayama,Tottori,Shimane,Okayama,Hiroshima,Yamaguchi,Tokushima,Kagawa,Ehime,Kochi,Fukuoka,Saga,Nagasaki,Kumamoto,Oita,Miyazaki,Kagoshima,Okinawa
2020/1/16,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
2020/1/17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
2020/1/18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
2020/1/19,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
2020/1/20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
2020/1/21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
```

#5. ファイルのコピー

##5-1. コピーの実施
パラメータ詳細は以下を参照：
- [S3.ServiceResource.Bucket](https://ibm.github.io/ibm-cos-sdk-python/reference/services/s3.html#S3.ServiceResource.Bucket)
- [S3.Bucket.copy](https://ibm.github.io/ibm-cos-sdk-python/reference/services/s3.html#S3.Bucket.copy)

```python
# コピー元ファイル情報
copy_source = {
    #  コピー元Bucket名
    "Bucket": "python-test-2022" ,
     #  コピー元File名
    "Key": "newly_confirmed_cases_daily.csv"
}
#コピー先 Bucket名
target_bucket = "python-test-2022" 
#コピー先 ファイル名(必要ならpathをつける)
target_file ="copytest/newly_confirmed_cases_daily.csv"

bucket = resource.Bucket(target_bucket)
bucket.copy(copy_source, target_file)
```

##5-2. 確認のためBucketの全ファイルのListを表示
```py
#確認
bucket = resource.Bucket(target_bucket)
for object in bucket.objects.all():
    print(object)
```
出力：

```sh
s3.ObjectSummary(bucket_name='python-test-2022', key='copytest/newly_confirmed_cases_daily.csv')
s3.ObjectSummary(bucket_name='python-test-2022', key='newly_confirmed_cases_daily.csv')
```

#6. ファイルの削除

##6-1. 削除の実施
パラメータ詳細は以下を参照：
- [S3.ServiceResource.Object](https://ibm.github.io/ibm-cos-sdk-python/reference/services/s3.html#object)
- [S3.Object.delete](https://ibm.github.io/ibm-cos-sdk-python/reference/services/s3.html#S3.Object.delete)

```python
#削除するファイルが入っている Bucket名
target_bucket = "python-test-2022" 
#削除ファイル名(必要ならpathをつける)
delete_file ="newly_confirmed_cases_daily.csv"

object = resource.Object(target_bucket, delete_file)
object.delete()
```

##6-2. 確認のためBucketの全ファイルのListを表示
```py
bucket = resource.Bucket(target_bucket)
for object in bucket.objects.all():
    print(object)
```
出力：

```sh
s3.ObjectSummary(bucket_name='python-test-2022', key='copytest/newly_confirmed_cases_daily.csv')
```

#7. ファイルのダウンロード

##7-1. ダウンロードの実施
パラメータ詳細は以下を参照：
- [S3.ServiceResource.Object](https://ibm.github.io/ibm-cos-sdk-python/reference/services/s3.html#object)
- [S3.Object.download_file](https://ibm.github.io/ibm-cos-sdk-python/reference/services/s3.html#S3.Object.download_file)

```python
#ダウンロードするファイルが入っている Bucket名
source_bucket = "python-test-2022" 
#ダウンロードするファイル名(必要ならpathをつける)
source_file ="copytest/newly_confirmed_cases_daily.csv"
# ローカルの保存先ファイル名(必要ならpathをつける)
local_file ="icos_newly_confirmed_cases_daily.csv"

object = resource.Object(source_bucket, source_file)
object.download_file(local_file)
```

##7-2. ダウンロード確認
とくにICOS特有のCodeではないですが、、、、。

```python
import os

#ダウンロード確認
if(os.path.isfile(local_file) == True):
    print('Download OK')
else:
    print('Download Failed')
```

出力：

```sh
Download OK
```

#8. まとめ
いかかがでしたか？　簡単なのでぜひいろいろやってみていただければと思います。

尚、最初にも書きましたが、使用しているCodeはgithubにnotebookで公開しています:
https://github.com/kyokonishito/icos_python/blob/main/icos_sample.ipynb

AWS S3のライブラリとほぼ一緒なのでさらにいろいろなサンプルは`AWS` `S3` `python`で検索するとよりたくさん出てくると思います。