目次

ConoHaのオブジェクトストレージをGoを使って操作する方法をご紹介します。オブジェクトストレージについての説明は以下のページにございます。

ConoHaのオブジェクトストレージについて(導入編)

SDKs – OpenStackで紹介されている
GophercloudというSDKを使います。

※上記の記事ではrackspace/gophercloudが紹介されていますが、gophercloud/gophercloudに移行されました。

ドキュメント:objectstorage – GoDoc

環境

下記のような環境で動作を確認しています。

$ cat /etc/centos-release
CentOS Linux release 7.6.1810 (Core) 
$ go version
go version go1.12.7 linux/amd64

使い方

[1] まずはGo Modulesを使うために設定をします。

$ go mod init objectstorage-conoha
go: creating new go.mod: module objectstorage-conoha
$ go get github.com/gophercloud/gophercloud
go: finding github.com/gophercloud/gophercloud v0.2.0
go: finding golang.org/x/sys v0.0.0-20190209173611-3b5209105503
go: finding golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67
go: finding gopkg.in/yaml.v2 v2.2.2
go: finding gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405
go: downloading github.com/gophercloud/gophercloud v0.2.0
go: extracting github.com/gophercloud/gophercloud v0.2.0

[2] APIの認証情報の設定

・環境変数で指定する場合

package main

import (
	"github.com/gophercloud/gophercloud/openstack"
)

func main() {
	_, err := openstack.AuthOptionsFromEnv()
	if err != nil {
		panic(err)
	}
}
ENV 設定する値 説明
OS_AUTH_URL https://identity.xxx.conoha.io/v2.0 identityのURL
OS_USERNAME gncuxxxxxxxx APIユーザー名
OS_PASSWORD APIパスワード
OS_TENANT_ID xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx テナントID

※下記のように出力された場合は環境変数に値が入っていない可能性があります。

$ go run main.go
panic: Missing environment variable [OS_AUTH_URL]

goroutine 1 [running]:
main.main()
        /root/docs/objectstorage_go/main.go:13 +0x30f
exit status 2

・直接指定する場合

option := gophercloud.AuthOptions{
	IdentityEndpoint: "https://identity.xxx.conoha.io/v2.0",
	Username:         "gncuxxxxxxxx",
	Password:         "xxxxxxxxxxxx",
	TenantID:         "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
}

[3] 認証の確認

下記のコードでトークンが表示された場合は認証に成功しています。

package main

import (
	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack"

	"fmt"
)

func main() {
	option, err := openstack.AuthOptionsFromEnv()
	if err != nil {
		panic(err)
	}

	provider, err := openstack.AuthenticatedClient(option)
	if err != nil {
		panic(err)
	}

	client, err := openstack.NewObjectStorageV1(provider, gophercloud.EndpointOpts{})
	if err != nil {
		panic(err)
	}

	fmt.Println(client.Token())
}

※下記のように表示された場合はテナントIDが指定されていない可能性がございます。

$ go run main.go
panic: No suitable endpoint could be found in the service catalog.

goroutine 1 [running]:
main.main()
        /root/docs/objectstorage_go/main.go:21 +0x1cd
exit status 2

[4] トークンの取得

トークンやトークンの期限を取得したい場合はExtractToken()を使う事で取得可能です。

authResult := provider.GetAuthResult().(tokens.CreateResult)
token, err := authResult.ExtractToken()
if err != nil {
	panic(err)
}
fmt.Println(token.ID)
fmt.Println(token.ExpiresAt)

トークンとエンドポイントを指定してリクエストする事も可能です。

provider := &gophercloud.ProviderClient{
	TokenID: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
}
client := &gophercloud.ServiceClient{
	ProviderClient: provider,
	Endpoint:       "https://object-storage.tyo1.conoha.io/v1/nc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
}

コンテナ一覧の取得

一覧を取得するには、EachPageとAllPageを使った2種類の方法が存在します。

EachPageを使った方法はイテレータとなっていてLimitというフィールドを指定する事で個数を指定する事ができます。また、無名関数内でfalseまたはerrを返す事で途中で止める事ができます。

どちらの方法もPrefixを指定することでコンテナ名で絞り込む事が可能です。

・EachPage

import (
	"github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers"
	"github.com/gophercloud/gophercloud/pagination"
)
listOpt := containers.ListOpts{
	Full: true,
	Prefix: "conoha_",
	Limit: 3,
}

pager := containers.List(client, listOpt)
pager.EachPage(func(p pagination.Page) (bool, error) {
	fmt.Println("[EachPage] start")
	containerList, err := containers.ExtractInfo(p)
	if err != nil {
		return false, err
	}

	for _, container := range containerList {
		fmt.Printf("%+vn", container)
	}

	fmt.Println("[EachPage] endn")
	return true, nil
})
-- EachPage start --
{Bytes:0 Count:1 Name:conoha_container}
{Bytes:0 Count:0 Name:conoha_container2}
{Bytes:0 Count:0 Name:conoha_container3}
-- EachPage end --

-- EachPage start --
{Bytes:0 Count:0 Name:conoha_container4}
{Bytes:0 Count:0 Name:conoha_container5}
{Bytes:0 Count:0 Name:conoha_container6}
-- EachPage end --

-- EachPage start --
{Bytes:0 Count:0 Name:conoha_container7}
-- EachPage end --

・AllPage

AllPageを使った方法は全てのコンテナの一覧を取得します。

import (
	"github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers"
)
listOpt := containers.ListOpts{
	Full: true,
	Prefix: "conoha_",
}
		
page, _ := containers.List(client, listOpt).AllPages()
containerList, _ := containers.ExtractInfo(page)
for _, container := range containerList {
	fmt.Printf("%+vn", container)
}
{Bytes:0 Count:1 Name:conoha_container}
{Bytes:0 Count:0 Name:conoha_container2}
{Bytes:0 Count:0 Name:conoha_container3}
{Bytes:0 Count:0 Name:conoha_container4}
{Bytes:0 Count:0 Name:conoha_container5}
{Bytes:0 Count:0 Name:conoha_container6}
{Bytes:0 Count:0 Name:conoha_container7}

コンテナの作成

コンテナの作成はcontainers.Createを使います。作成できなかった場合はresult.Errにエラーが入ります。

result := containers.Create(client, "conoha_container", nil)
if result.Err != nil {
	panic(result.Err)
} else {
	fmt.Println(result)
}

オブジェクトのアップロード

オブジェクトのアップロードはobjects.Createを使います。

import (
	"github.com/gophercloud/gophercloud/openstack/objectstorage/v1/objects"

	"os"
)
file, err := os.Open("./testfile")
if err != nil {
	panic(err)
}
defer file.Close()

opt := objects.CreateOpts {
	Content: file,
}

result := objects.Create(client, "container_name", "file_name", opt)
if result.Err != nil {
	panic(result.Err)
} else {
	fmt.Printf("%+vn", result)
}

下記のように表示された場合はファイルのサイズが5GBを超えている可能性があります。その場合は、Static Large Objectという機能を使ってアップロードする必要があります。

panic: Expected HTTP response code [] when accessing [PUT https://object-storage.tyo1.conoha.io/v1/nc_8684317cf1f3492eb558714b95d5d080/container_name/file_name], but got 413 instead
<html><h1>Request Entity Too Large</h1><p>The body of your request was too large for this server.</p></html>

gophercloud/utilsというライブラリでサポートされているのでこれを使う事でアップロードが可能です。

$ go get github.com/gophercloud/utils

SegmentSizeを指定する事で1ファイルのサイズを決める事ができます。

import "github.com/gophercloud/utils/openstack/objectstorage/v1/objects"

opt := &objects.UploadOpts{
	Content: file,
	SegmentSize: 1024 * 1024 * 512,
	UseSLO: true,
}

result, err := objects.Upload(client, "container_name", "file_name", opt)
if err != nil {
	panic(err)
} else {
	fmt.Printf("%+vn", result)
}
$ go run.main.go
&{Action:upload_action Container:container_name LargeObject:false Object:file_name Path: Status:uploaded Success:true}

オブジェクトのダウンロード

オブジェクトのダウンロードはobjects.Downloadを使います。コンテナやオブジェクトが存在しなかった場合はresult.Errにエラーが入ります。

result := objects.Download(client, "container_name", "file_name", nil)
if result.Err != nil {
	panic(result.Err)
} else {
	content, err := result.ExtractContent()
	if err != nil {
		panic(err)
	}
	
	fmt.Println(string(content))
}

オブジェクトの公開

オブジェクトの公開はcontainers.Updateを使い、コンテナのメタデータをアップデートする事で公開が可能です。

import (
	"github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers"
)
opt := containers.UpdateOpts {
	ContainerRead: ".r:*",
}
result := containers.Update(client, "container_name", opt)
if result.Err != nil {
	panic(result.Err)
} else {
	fmt.Printf("%+vn", result)
}

まとめ

今回はGophercloudというSDKを使って、ConoHaのオブジェクトストレージを操作する方法をご紹介しました。Gophercloudは他にもVPSの作成であったり、セキュリティグループの設定を簡単に行う事ができます。

問題は解決できましたか?

お役立ち情報

ConoHaではサポートコンテンツの他にも以下のようなお役立ち情報をご用意しております。ぜひご活用ください。