Skip to content

Commit

Permalink
sacloud/api-client-goの導入 (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
yamamoto-febc authored Mar 22, 2022
1 parent 1235e84 commit 93991a2
Show file tree
Hide file tree
Showing 11 changed files with 171 additions and 145 deletions.
10 changes: 2 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,8 @@ import (
)

func main() {
token := os.Getenv("SAKURACLOUD_ACCESS_TOKEN")
secret := os.Getenv("SAKURACLOUD_ACCESS_TOKEN_SECRET")

client := &objectstorage.Client{
Token: token,
Secret: secret,
}
ctx := context.Background()
ctx := context.Background()
client := &objectstorage.Client{} // デフォルトでusacloud互換プロファイル or 環境変数(SAKURACLOUD_ACCESS_TOKEN{_SECRET})が利用される

// サイト一覧を取得
siteOp := objectstorage.NewSiteOp(client)
Expand Down
48 changes: 8 additions & 40 deletions acceptance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,24 @@ import (
"bytes"
"context"
"io"
"math/rand"
"net/http"
"os"
"testing"
"time"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/s3"
objectstorage "github.com/sacloud/object-storage-api-go"
v1 "github.com/sacloud/object-storage-api-go/apis/v1"
"github.com/sacloud/sacloud-go/pkg/envvar"
"github.com/sacloud/sacloud-go/pkg/testutil"
"github.com/stretchr/testify/require"
)

const (
siteId = "isk01" // Note: 本来はサイトAPI経由で取得すべきだが現状ではサイトが1つしかないため定数として保持/利用する
charSet = "abcdefghijklmnopqrstuvwxyz012346789" // ランダム名生成で利用する文字
siteId = "isk01" // Note: 本来はサイトAPI経由で取得すべきだが現状ではサイトが1つしかないため定数として保持/利用する
)

func init() {
rand.Seed(time.Now().UTC().UnixNano())
}

// TestAccSiteAndStatusAPI サイト/ステータス関連APIの疎通確認
func TestAccSiteAndStatusAPI(t *testing.T) {
skipIfNoAPIKey(t)
Expand Down Expand Up @@ -83,7 +77,7 @@ func TestAccBucketHandling(t *testing.T) {
skipIfNoEnv(t, "SACLOUD_OJS_ACCESS_KEY_ID", "SACLOUD_OJS_SECRET_ACCESS_KEY")

ctx := context.Background()
bucketName := randomName(28)
bucketName := testutil.Random(28, testutil.CharSetAlpha)

// Step1: バケット作成
bucketOp := objectstorage.NewBucketOp(accTestClient)
Expand Down Expand Up @@ -145,7 +139,7 @@ func TestAccAccessToBucketObjectWithPermissionKey(t *testing.T) {
skipIfNoAPIKey(t)

ctx := context.Background()
bucketName := randomName(28)
bucketName := testutil.Random(28, testutil.CharSetAlpha)

// Step1: バケット作成
bucketOp := objectstorage.NewBucketOp(accTestClient)
Expand Down Expand Up @@ -248,27 +242,9 @@ func TestAccAccessToBucketObjectWithPermissionKey(t *testing.T) {
require.NoError(t, bucketOp.Delete(ctx, siteId, bucketName))
}

var accTestClient = func() *objectstorage.Client {
token := os.Getenv("SAKURACLOUD_ACCESS_TOKEN")
secret := os.Getenv("SAKURACLOUD_ACCESS_TOKEN_SECRET")
rootURL := os.Getenv("SAKURACLOUD_OJS_ROOT_URL")

if rootURL == "" {
rootURL = defaultServerURL
}

httpClient := &http.Client{}

client := &objectstorage.Client{
Token: token,
Secret: secret,
APIRootURL: serverURL,
Trace: os.Getenv("SAKURACLOUD_TRACE") != "",
HTTPClient: httpClient,
}

return client
}()
var accTestClient = &objectstorage.Client{
APIRootURL: envvar.StringFromEnv("SAKURACLOUD_OJS_ROOT_URL", defaultServerURL),
}

// skipIfNoEnv 指定の環境変数のいずれかが空の場合はt.SkipNow()する
func skipIfNoEnv(t *testing.T, envs ...string) {
Expand All @@ -289,11 +265,3 @@ func skipIfNoEnv(t *testing.T, envs ...string) {
func skipIfNoAPIKey(t *testing.T) {
skipIfNoEnv(t, "SAKURACLOUD_ACCESS_TOKEN", "SAKURACLOUD_ACCESS_TOKEN_SECRET")
}

func randomName(strlen int) string {
result := make([]byte, strlen)
for i := 0; i < strlen; i++ {
result[i] = charSet[rand.Intn(len(charSet))]
}
return string(result)
}
36 changes: 30 additions & 6 deletions accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ func NewAccountOp(client *Client) AccountAPI {
}

func (op *accountOp) Create(ctx context.Context, siteId string) (*v1.Account, error) {
resp, err := op.client.apiClient().CreateAccountWithResponse(ctx, siteId)
apiClient, err := op.client.apiClient()
if err != nil {
return nil, err
}
resp, err := apiClient.CreateAccountWithResponse(ctx, siteId)
if err != nil {
return nil, err
}
Expand All @@ -65,7 +69,11 @@ func (op *accountOp) Create(ctx context.Context, siteId string) (*v1.Account, er
}

func (op *accountOp) Read(ctx context.Context, siteId string) (*v1.Account, error) {
resp, err := op.client.apiClient().GetAccountWithResponse(ctx, siteId)
apiClient, err := op.client.apiClient()
if err != nil {
return nil, err
}
resp, err := apiClient.GetAccountWithResponse(ctx, siteId)
if err != nil {
return nil, err
}
Expand All @@ -77,15 +85,23 @@ func (op *accountOp) Read(ctx context.Context, siteId string) (*v1.Account, erro
}

func (op *accountOp) Delete(ctx context.Context, siteId string) error {
resp, err := op.client.apiClient().DeleteAccountWithResponse(ctx, siteId)
apiClient, err := op.client.apiClient()
if err != nil {
return err
}
resp, err := apiClient.DeleteAccountWithResponse(ctx, siteId)
if err != nil {
return err
}
return resp.Result()
}

func (op *accountOp) CreateAccessKey(ctx context.Context, siteId string) (*v1.AccountKey, error) {
resp, err := op.client.apiClient().CreateAccountKeyWithResponse(ctx, siteId)
apiClient, err := op.client.apiClient()
if err != nil {
return nil, err
}
resp, err := apiClient.CreateAccountKeyWithResponse(ctx, siteId)
if err != nil {
return nil, err
}
Expand All @@ -97,7 +113,11 @@ func (op *accountOp) CreateAccessKey(ctx context.Context, siteId string) (*v1.Ac
}

func (op *accountOp) ReadAccessKey(ctx context.Context, siteId, accessKeyId string) (*v1.AccountKey, error) {
resp, err := op.client.apiClient().GetAccountKeyWithResponse(ctx, siteId, v1.AccessKeyID(accessKeyId))
apiClient, err := op.client.apiClient()
if err != nil {
return nil, err
}
resp, err := apiClient.GetAccountKeyWithResponse(ctx, siteId, v1.AccessKeyID(accessKeyId))
if err != nil {
return nil, err
}
Expand All @@ -109,7 +129,11 @@ func (op *accountOp) ReadAccessKey(ctx context.Context, siteId, accessKeyId stri
}

func (op *accountOp) DeleteAccessKey(ctx context.Context, siteId, accessKeyId string) error {
resp, err := op.client.apiClient().DeleteAccountKeyWithResponse(ctx, siteId, v1.AccessKeyID(accessKeyId))
apiClient, err := op.client.apiClient()
if err != nil {
return err
}
resp, err := apiClient.DeleteAccountKeyWithResponse(ctx, siteId, v1.AccessKeyID(accessKeyId))
if err != nil {
return err
}
Expand Down
12 changes: 10 additions & 2 deletions buckets.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ func (op *bucketOp) Create(ctx context.Context, siteId, bucketName string) (*v1.
ClusterId: siteId,
}

resp, err := op.client.apiClient().CreateBucketWithResponse(ctx, v1.BucketName(bucketName), params)
apiClient, err := op.client.apiClient()
if err != nil {
return nil, err
}
resp, err := apiClient.CreateBucketWithResponse(ctx, v1.BucketName(bucketName), params)
if err != nil {
return nil, err
}
Expand All @@ -60,7 +64,11 @@ func (op *bucketOp) Delete(ctx context.Context, siteId, bucketName string) error
ClusterId: siteId,
}

resp, err := op.client.apiClient().DeleteBucketWithResponse(ctx, v1.BucketName(bucketName), params)
apiClient, err := op.client.apiClient()
if err != nil {
return err
}
resp, err := apiClient.DeleteBucketWithResponse(ctx, v1.BucketName(bucketName), params)
if err != nil {
return err
}
Expand Down
101 changes: 52 additions & 49 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,12 @@
package objectstorage

import (
"context"
"fmt"
"net/http"
"runtime"
"strings"
"sync"

"github.com/hashicorp/go-retryablehttp"
sacloudhttp "github.com/sacloud/go-http"
client "github.com/sacloud/api-client-go"
v1 "github.com/sacloud/object-storage-api-go/apis/v1"
)

Expand All @@ -36,34 +33,32 @@ var UserAgent = fmt.Sprintf(
Version,
runtime.GOOS,
runtime.GOARCH,
sacloudhttp.DefaultUserAgent,
client.DefaultUserAgent,
)

// Client APIクライアント
type Client struct {
// Profile usacloud互換プロファイル名
Profile string

// Token APIキー: トークン
Token string
// Token APIキー: シークレット
Secret string

// AcceptLanguage APIリクエスト時のAccept-Languageヘッダーの値
AcceptLanguage string

// Gzip APIリクエストでgzipを有効にするかのフラグ
Gzip bool

// APIRootURL APIのリクエスト先URLプレフィックス、省略可能
APIRootURL string

// Trace トレースログ出力フラグ
Trace bool
// Options HTTPクライアント関連オプション
Options *client.Options

// HTTPClient APIリクエストで使用されるHTTPクライアント
//
// 省略した場合はhttp.DefaultClientが使用される
HTTPClient *http.Client
// DisableProfile usacloud互換プロファイルからの設定読み取りを無効化
DisableProfile bool
// DisableEnv 環境変数からの設定読み取りを無効化
DisableEnv bool

initOnce sync.Once
factory *client.Factory
}

func (c *Client) serverURL() string {
Expand All @@ -77,47 +72,55 @@ func (c *Client) serverURL() string {
return v
}

func (c *Client) httpClient() *http.Client {
client := http.DefaultClient
if c.HTTPClient != nil {
client = c.HTTPClient
}

func (c *Client) init() error {
var initError error
c.initOnce.Do(func() {
if c.Trace {
client.Transport = &sacloudhttp.TracingRoundTripper{
Transport: client.Transport,
var opts []*client.Options
// 1: Profile
if !c.DisableProfile {
o, err := client.OptionsFromProfile(c.Profile)
if err != nil {
initError = err
return
}
opts = append(opts, o)
}

// 2: Env
if !c.DisableEnv {
opts = append(opts, client.OptionsFromEnv())
}

// 3: UserAgent
opts = append(opts, &client.Options{
UserAgent: UserAgent,
})

// 4: Options
if c.Options != nil {
opts = append(opts, c.Options)
}

// 5: フィールドのAPIキー
opts = append(opts, &client.Options{
AccessToken: c.Token,
AccessTokenSecret: c.Secret,
})

c.factory = client.NewFactory(opts...)
})
return client
return initError
}

func (c *Client) apiClient() *v1.ClientWithResponses {
httpClient := &sacloudhttp.Client{
AccessToken: c.Token,
AccessTokenSecret: c.Secret,
UserAgent: UserAgent,
AcceptLanguage: c.AcceptLanguage,
Gzip: c.Gzip,
CheckRetryFunc: func(ctx context.Context, resp *http.Response, err error) (bool, error) {
if ctx.Err() != nil {
return false, ctx.Err()
}
if err != nil {
return retryablehttp.DefaultRetryPolicy(ctx, resp, err)
}
if resp.StatusCode == 0 { // ステータスコードに応じてリトライしたい場合はここで対応
return true, nil
}
return false, nil
},
HTTPClient: c.httpClient(),
func (c *Client) apiClient() (*v1.ClientWithResponses, error) {
if err := c.init(); err != nil {
return nil, err
}

return &v1.ClientWithResponses{
ClientInterface: &v1.Client{
Server: c.serverURL(),
Client: httpClient,
Client: c.factory.NewHttpRequestDoer(),
},
}
}, nil
}
Loading

0 comments on commit 93991a2

Please sign in to comment.