IBM Cloud Object Storage トラブルシューティング

# IBM Cloud のオブジェクトストレージでハマったので対策をメモ

## その１．AWS S3 CLIでハマった

インストール

```
$ pip install awscli

Collecting awscli
  Downloading https://files.pythonhosted.org/packages/7b/bf/ee

　　中略

Successfully installed PyYAML-5.1.2 awscli-1.16.290 botocore-1.13.26 docutils-0.15.2 jmespath-0.9.4 pyasn1-0.4.8 python-dateutil-2.8.0 rsa-3.4.2 s3transfer-0.2.1 six-1.13.0
```

インストールできたか、バージョンを表示する動作検査

```
$ $ aws --version
aws-cli/1.16.290 Python/3.4.10 Linux/3.10.0-957.5.1.el7.x86_64 botocore/1.13.26
```

### 1. [aws s3 ls]コマンドで、バケットのファイル一覧を表示できないのですが。

```
$ aws s3 ls

Could not connect to the endpoint URL: "https://s3.jp-tok-standard.amazonaws.com/"
# そんな名前のエンドポイントはありませんよ。と言っている
```

対策）[aws s3]の参照先は[amazonaws.com]なので、CLIオプション[--endpoint-url]でエンドポイントに IBM Cloud の東京リージョンURLを指定します。

```
$ aws --endpoint-url "http://s3.jp-tok.cloud-object-storage.appdomain.cloud/" s3 ls
2019-11-20 23:03:21 backetname1
2019-11-30 22:39:11 backetname2
# 既存バケットが２つ表示された
```

### 2. [aws configure]で指定するキーやリージョンはどこで教えてくれるの？
ここ（↓）のパラメータに指定するものは[サービス資格情報]で取得します。

```
$ aws configure

AWS Access Key ID []:　パラメータ１
AWS Secret Access Key []:　パラメータ２
Default region name []:　パラメータ３
Default output format []:　パラメータ４
```
オブジェクトストレージの[サービス資格情報]で新規に[新規資格情報(+)]を追加するときに"HMAC資格情報を含める"に[v]チェックをすると、[aws config]用のアクセスキーIDとシークレットアクセスキーを取得できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/d884af79-c0fd-9758-1f59-6a4a8e40c440.png)

この画面の[資格情報の表示▼]をクリックすると表示される[access_key_id]と[secret_access_key]がパラメータ１と２です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/a46b549b-08b5-52db-a53f-f42e3b2990c5.png)

そして[default region name]のパラメータ３は、[ap-northeast-1]じゃないですからね。IBM Cloud の場合は、日本リージョンの場合: jp-tok-standard / jp-tok-vault / jp-tok-cold / jp-tok-flex のいずれか。ストレージ・クラスを[Standard]で作成した場合は[jp-tok-standard]です。
最後のパラメータ４は[json]でいいですよね。

> 参考　リージョン名一覧
>  <https://cloud.ibm.com/docs/services/cloud-object-storage?topic=cloud-object-storage-classes&locale=ja#classes-locationconstraint>

では[aws config]の設定を実行します。

```
$ aws configure
AWS Access Key ID [****************6024]:
AWS Secret Access Key [****************9681]:
Default region name [jp-tok-standard]:
Default output format [json]:
```

### 3. [aws cli]で新しいバケットを作成してみる

```
▼IBM Cloud のエンドポイントURLは何度も使うおんでOSの環境変数に覚えさせます
$ export S3_ENDPOINT="http://s3.jp-tok.cloud-object-storage.appdomain.cloud/"

▼新しいバケットを作成します。
$ aws --endpoint-url ${S3_ENDPOINT} s3 mb s3://newbucket

▼そんな安易な名前は既に使われています
make_bucket failed: s3://newbucket An error occurred (BucketAlreadyExists) when 
calling the CreateBucket operation: Container newbucket exists with a different storage location than requested

▼それならば
$ aws --endpoint-url ${S3_ENDPOINT} s3 mb s3://newbucket2019

▼新しいバケットが作成されました。
make_bucket: newbucket2019

```
[aws cli]で新しいバケット"newbucket2019"を作成できた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/5d43a62c-6fe6-7873-e4fa-71ea13473064.png)

### 4. [aws cli]でファイルをアップロードしてみる

```
$ aws --endpoint-url ${S3_ENDPOINT} s3 cp picture.jpg s3://newbucket2019
upload: ./picture.jpg to s3://newbucket2019/picture.jpg
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/6d393f36-14be-ab38-3903-409dd4b5394e.png)

ここまで動いた。おめでとう。

### 5. [aws sdk for python]でファイルアップロードできない。ただ今、対策不明。誰かヘルプミー。
[aws cli]でファイルアップロードできたので、今度はpythonでスクリプトを組んでみたのだけど。

```
# このスクリプトではアップロードできません。どこが違うのでしょうか。
# -*- coding: utf-8 -*-
import sys
import boto3

if __name__=="__main__":
    # AWS S3のバケットにアップロードする
    bucket_name = "robocamera"
    filename = "face3.png"
    s3 = boto3.resource(service_name='s3', endpoint_url='http://s3.jp-tok.cloud-object-storage.appdomain.cloud')
    s3.Bucket(bucket_name).upload_file(filename, filename)
```
エラー。認証が一致していない様だが、[ibm_boto3]というモノがあるらしいので中途半端に乗り換える。

```
boto3.exceptions.S3UploadFailedError: Failed to upload face3.png to robocamera/face3.png: An error occurred (SignatureDoesNotMatch) when calling the PutObject operation: The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. For more information, see REST Authentication and SOAP Authentication for details.
```

### 6. 今度は[ibmcloud sdk for python]で[ibm_boto3]を準備する。

```
# インストール
$ pip install ibm-cos-sdk

# 環境変数を設定する
$ export IBM_APIKEY=ddZg**********************jGkB3
$ export IBM_RESOURCE_INSTANCE_ID=2ab*******************aa3c::
```

下記参考に従ってpythonスクリプトを作り直し。

```
# ひえええ。教科書どおりのはずなんだけど...。
# 自分PCは、python2.7と3.4が混在しててibm-sdkのpathが間違ってるんだろうな、たぶん。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
import time
import ibm_boto3
from ibm_botocore.client import Config, ClientError

if __name__=="__main__":

    # オブジェクトストレージの場所と認証
    auth_endpoint = "https://iam.cloud.ibm.com/identity/token"
    service_endpoint = 'http://s3.jp-tok.cloud-object-storage.appdomain.cloud'

    s3 = ibm_boto3.resource("s3",
        ibm_api_key_id          = os.environ['IBM_APIKEY'],
        ibm_service_instance_id = os.environ['IBM_RESOURCE_INSTANCE_ID'],
        ibm_auth_endpoint       = auth_endpoint,
        config                  = Config(signature_version="oauth"),
        endpoint_url            = service_endpoint
    )

    # IBM Cloud Object Storage (S3) のバケットにアップロードする

    s3.Bucket("robocamera").upload_file("robopicture.jpg", "B.jpg", ExtraArgs={"ContentType": "image/jpeg"})

    #s3.upload_file("robopicture.jpg", "robocamera", "robopicture.jpg")
    #s3 = boto3.resource(service_name='s3', endpoint_url='http://s3.jp-tok.cloud-object-storage.appdomain.cloud')
    #s3.Bucket(bucket_name).upload_file("robopicture.jpg", filename)

```

エラー。importまわり。

```
s3 = ibm_boto3.resource("s3",
AttributeError: 'module' object has no attribute 'resource'
とか
from ibm_botocore.client import Config, ClientError
ImportError: No module named ibm_botocore.client
とか
```

> 参考　<https://cloud.ibm.com/docs/services/cloud-object-storage/libraries?topic=cloud-object-storage-python&locale=ja>

んんんーーー。一旦、保留にして、cURLでAPIから再確認しよっと。
cURLなら動いた。動いた環境はこちら。

## その２．オブジェクトストレージのパブリックURLでエラーになるのですが

### 1. "This XML file does not appear ..."に続けて[**Access Denied**]になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/5ccf29a1-5472-77cb-d325-cee2483353f2.png)

対策）バケットにアクセスする権限を許可してないかも。下図の手順で、画面に従ってパブリックアクセスの許可を追加します。インターネットに公開されちゃうのでセキュリティには気をつけてね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/fe614cdc-d0a6-2557-be6d-420999449fd0.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/fbca711a-8d05-bade-c458-063930f3d7d9.png)

### 2. "This XML file does not appear ..."に続けて[**key does not exist**]になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/a932366d-5ab5-0f4d-8876-cb09a118fde2.png)

対策）バケットにそのファイルが見つかりません。ファイル名を再確認するか、クラウド管理ポータルでそのファイルが保存されていることを確認しよっと。

## 最後に
設定ミスの原因を見つけるのに何時間もかけてしまったので、今後もハマりどころに直面したらメモ追加します。