GO言語 から bluemixのObject Strageを使用する。


経緯

bluemix上にデプロイしている自作のGO言語アプリケーションで、大容量ストレージが必要になってきたため、bluemixで提供されているストレージサービスを調べてみました。
使用できるサービスは、BlockStorage、FileStorage、ObjectStorageの3つですが、ObjectStorage以外はどれもちゃんとしたサーバーからアクセスする前提となっているようで、CloudFoundryからは使用出来ないようです。(FileStorageを使用しようと試行錯誤しましたが、出来ませんでした。)
で、このObjectStorageを使用する場合も、Node.jsでアクセスするサンプルコードは見つかるのですが、GO言語のものが英語サイトでも見つかりませんでした。
結局、自力で解決したので、その辺りのノウハウを共有したいと思います。

準備

接続情報取得

まず、bluemixコンソールから、下記の手順で接続情報を確認します。

  1. アプリから”ObjectStorage”を選択

  2. 左側メニューの “サービス資格情報”を選択

  3. メイン部分に表示される”サービス資格情報”内の”詳細の表示”ボタンを選択

すると、下記のようなJSON形式の情報が表示されます。これをどこかにメモります。

{
    "Object-Storage": [
        {
            "credentials": {
                "auth_url": "https://identity.open.softlayer.com",
                "project": "…",
                "projectId": "…",
                "region": "…",
                "userId": "…",
                "username": "※1",
                "password": "※2",
                "domainId": "※3",
                "domainName": "…",
                "role": "admin"
            },

OpenStack Swiftライブラリインストール

次にOpenStack Swiftにアクセスするためのライブラリ取得します。

go get github.com/ncw/swift

準備は、以上で完了です。

実装

下記は、接続から"test"という名前でコンテナを作成するまでの実装サンプルです。
swift.connection部分を自分用に置き換えれば、そのまま使用できると思います。
このコードで、ローカルマシンでも、bluemixにデプロイした状態でも動作します。

import (
// …
"github.com/ncw/swift"
// …
)

var c = swift.Connection{}
var CONNAME = "test"


func init() error {
    c = swift.Connection{
        UserName: "※1",
        ApiKey:   "※2",
        AuthUrl:  "https://identity.open.softlayer.com/v3/",
        DomainId: "※3",
    }
    // Authenticate
    err := c.Authenticate()
    if err != nil {
        return err
    }
    // コンテナ名一覧を取得
    containers, err := c.ContainerNames(nil)
    if err != nil {
        return err
    }
        // 探しているコンテナ名があるか
    found := false
    for _, name := range containers {
        if name == CONNAME {
            found = true
            break
        }
    }
        // 無ければ作成
    if !found {
        err = c.ContainerCreate(CONNAME, nil)
        return err
    }
    return nil
}

ファイル保存、読み込みはこんな感じです。

    // 保存
    out, err := c.ObjectCreate(CONNAME, "ファイル名", true, "", "", nil)
    if err != nil {
        // エラー処理
    }
    if size, err := out.Write([]byte("データ")); err!=nil {
        // エラー処理
    }
    if err = out.Close(); err != nil {
                // エラー処理
    }
    // 読み込み
    data, err := c.ObjectGetBytes(CONNAME, "ファイル名")