GCSへのファイル転送をVBScriptで実装してみた

##はじめに
外部サービスとのデータ連携で[Google Cloud Storage(以下GCS) ](https://cloud.google.com/storage/?hl=ja)を利用しました。
[Cloud Client Libraries](https://cloud.google.com/storage/docs/reference/libraries)でサポートされていない**VBScript**で実装したため、その内容をまとめます。

##前提
- 処理形式・・・バッチ
- アウトプット・・・TSVファイル
- 言語・・・VBScript

今回は既存改修だったため、上記の前提となりました。
※ビジネスロジックの変更は必要なく、転送先の変更が必要だったため。

##転送方式
GCSにファイル転送する方法としては大きく２つあると思います。

① [API（XML、JSON）を利用して転送する](https://cloud.google.com/storage/docs/json_api/)
② [gsutilをインストールしてコマンドラインで転送する](https://cloud.google.com/storage/docs/gsutil)

比較すると、

**①の場合**
　・提供されているライブラリを利用するだけで良い
　・また、認証周りがよりシームレスに行える
　・実装例が豊富にある

**②の場合**
　・サーバーへのインストールが必要になる
　・故に、再セットアップ、あるいはリプレイスの際に再インストールが必要になる
　・プログラムに組み込んだ前例が見当たらない

##採用した方式
本来であれば①の方式が望ましいと思いますが、前提の通り、言語が**VBScript**という制約のもと（ライブラリでサポートされていないため）②の一択となりました。

※**JSON API**の自前実装をトライしたのですが、認証のアカウントコード取得でうまくいきませんでした。トライした内容を紹介するにはボリュームがあるので割愛します。

##gsutil（Google Cloud SDK）のインストール
まずはgsutilをインストールします。gsutilはGoogle Cloud SDKに内包されています。

***１．[Google Cloud SDK のインストーラをダウンロードする](https://cloud.google.com/sdk/docs/?hl=ja#install_the_latest_cloud_tools_version_cloudsdk_current_version)***

***２．ダウンロードしたインストーラを実行する***

***３．「Next」を押下する***
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440367/b613d2ee-c00e-4476-408a-896ffdc0bfa7.png)

***４．「I Agree」を押下する***
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440367/8e018fb0-6f5b-a379-ecb1-2d6fce987208.png)

***５．デフォルトのまま「Next」を押下する***
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440367/09b8511b-7862-3fec-decc-f1e79eb55db5.png)

***６．デフォルトのまま「Next」を押下する***
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440367/22cfded1-089f-6c43-0ba2-51a0900761b4.png)

***７．デフォルトのまま「Install」を押下する***
※Python 2.7.9 以降が入っていればPythonのチェックを外して良い
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440367/576b4946-118b-8525-0d7d-33930ec1ce19.png)

***８．Install完了後、「Next」を押下する***
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440367/84d4e9c1-b7e0-d2d8-a778-d0a6f924648b.png)

***９．セットアップ完了画面でチェックを全て外し「Finish」を押下する***
※キャプチャではチェックが入っているが必要ない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440367/1189e67f-00e0-22a9-95c7-ebe019e91fff.png)

##構成
ものすごくザックリ紹介しますが、構成はこんな感じです。送信コマンドをbatファイルで別にした理由としては、
　・今後、複数の転送先が予想されるから
　・それにともない複数のプログラムから利用できたら便利だし管理しやすいから
　・また、リカバリーを行う際、batファイル単体実行でファイル送信が可能になるから
　　　　∟個人的な感覚ですが、AWSなんかと比べてGCPは管理画面が操作しにくいです
　　　　∟または、操作権限をもたないメンバーなどがリカバリーを行う際にも有効かと思います

という感じで少しだけ汎用的な作りにしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440367/a05af30e-f8f6-60fb-4205-a9bf0e5b5f3a.png)


##実装
***１．[GoogleCloudPlatform](https://console.cloud.google.com/storage/)でサービスアカウントを作成する***
　　・参考：[Cloud Client Libraries](https://cloud.google.com/storage/docs/reference/libraries)の「認証のセットアップ」

***２．作成したアカウントのサービスアカウントファイル（JSONファイル）をダウンロードする***

```ruby:service_account.json
{
  "type": "service_account",
  "project_id": "project_id",
  "private_key_id": "*************",
  "private_key": "-----BEGIN PRIVATE KEY-----\**********\n-----END PRIVATE KEY-----\n",
  "client_email": "*****@******.iam.gserviceaccount.com",
  "client_id": "*************",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/*************.iam.gserviceaccount.com"
}
```

***３．バケット、またはフォルダーを作成する（転送先ディレクトリを作成する）***

***４．batファイルを作成する***

```ruby:SendFile.bat
@echo off
SETLOCAL
SET ACCOUNT_SERVICE=%1
SET PROJECT_ID=%2
SET CLIENT_EMAIL=%3
SET INPUT_FILE=%4
SET BUCKET_FOLDER=%5
SET DESTINATION=gs://%BUCKET_FOLDER%
@echo on

gcloud auth activate-service-account %CLIENT_EMAIL% --key-file %ACCOUNT_SERVICE% --project %PROJECT_ID% && gsutil cp %INPUT_FILE% %DESTINATION%
@echo return code：%errorlevel%

@echo off
ENDLOCAL
if not %errorlevel% == 0 (
    exit /B 1
)
exit /B 0
```

***５．VBScriptでbatファイルの実行処理を実装する***

```ruby:SendFile.wsf
Public Function SendFile()
	Dim Shell : Set Shell = CreateObject("WScript.Shell")
	Dim batPath : batPath = "SendFile.batパス"
	Dim batLogPath : batLogPath = "bat.logパス"
	Dim accountServicePath : accountServicePath = "アカウント名.jsonパス"
	Dim projectId : projectId = "projectId" 
	Dim clientEmail : clientEmail = 'clientEmail'
	Dim bucketName : bucketName = "bucketName"
	Dim folderName : folderName = "folderName"
	Dim filePath : filePath = "送信ファイルパス"

	Dim cmdLine : cmdLine = batPath & " " & _
				            accountServicePath & " " & _
				            projectId & " " & _
				            clientEmail & " " & _
				            filePath & " " & _
				            bucketName & g_GcsFolderName & _
				            " >>" & batLogPath
	
	Dim result : result = Shell.Run(cmdLine,0,true)
End Function
```

##最後に
この方式でも動作に問題はありません。ただし、**転送方式**で記載した通り、どこかで再セットアップ作業が必要になります。その影響で「忘れていてトラブルを招いた」なんてことも懸念されますし、その辺りの管理の手間にも繋がります。外部APIはライブラリが提供されていることがほとんどなので、これを機に主流言語で構築し直すのが好ましいと感じました。

##参考まとめ
- Google Cloud Storage概要
　https://cloud.google.com/storage/?hl=ja
- Cloud Storage Client Libraries 
　https://cloud.google.com/storage/docs/reference/libraries
- Google Cloud Storage JSON API の概要
　https://cloud.google.com/storage/docs/json_api/
- gsutil ツール 
　https://cloud.google.com/storage/docs/gsutil
- Google Cloud SDK のドキュメント 
　https://cloud.google.com/sdk/docs/?hl=ja#install_the_latest_cloud_tools_version_cloudsdk_current_version