Open11

Google Drive へ gdrive でファイルアップロード

hankei6kmhankei6km

GCP と Google Drive 側の設定

Drive API の有効化

$ gcloud services enable drive.googleapis.com --project="${PROJECT_ID}"

サービスアカウントを用意(手順は省略)。

Google Drive にテスト用のフォルダーを作成し共有設定で編集者にサービスアカウントを追加。

hankei6kmhankei6km

アップロード

サービスアカウントの鍵を作成し以下のようにする。

$ ./gdrive --service-account gha-creds-test-temp.json -c . upload --parent "<フォルダーの ID>" test.txt
  • --service-account - サービスアカウントの鍵ファイル
  • -c - gdrive の設定ファイルのパス(サービスアカウントの鍵ファイルのパス名を特定するために必要)
  • --parent - 共有した フォルダーの ID
hankei6kmhankei6km

同じものをアップロードした場合、別の ID が割り振られる(ドライブ上でも別のファイルになる)。

hankei6kmhankei6km

引っかかったところ

ためしに共有設定なしで実行してみた場合。

--parent なしだとアップロードが成功する。id も割り振られるがファイルが見当たらない。ファイルはどこに消えた?

--parent をつけると Failed to get file: googleapi: Error 404: File not found: "フォルダーの ID" となる。「ID の指定の仕方違うのかな?」と少し悩んだが共有したらアップロードできたので、そういうものらしい。

hankei6kmhankei6km

サービスアカウントとドライブ

前のコメントでどこかにアップロードされたファイルは $ gdrive info で ViewURL がわかった。

ブラウザーで開いてみると「アクセス権が必要です」と言われる。

オーナー(?)がサービスアカウントのファイルが通常ユーザーの管理していないフォルダー(?)にアップロードされたのでこうなる(のかな?)

ならばと、ファイルが保存されているフォルダー(parent)を info で確認すると name と path がMy Drive になっている。

サービスアカウントにもドライブが付与されている?

hankei6kmhankei6km

$ gdrive mkdir して一般ユーザーと共有したあとに $ gdrive upload したら参照できた。

$ gdrive about で確認すると別ドライブのようなのだが、少し調べた感じでははっきりした情報が出てこない。

一般ユーザーのフォルダーを共有する予定なので、この辺はとりあえず保留。

hankei6kmhankei6km

アップロード(既存ファイルは上書き)

アップロード先フォルダーに同名ファイルがあれば上書きしたかった(同一 ID のファイルにしたかった)のでとりあえずのスクリプト作成。

同名ファイルが複数あった場合は最初にヒットしたもが上書きされる。

2022-03-23 スクリプト修正

send.sh
#!/bin/bash
set -e

SA="$(basename "gha-creds-test-temp.json")"
GDRIVE="./gdrive"

FILE_ID="$("${GDRIVE}" --service-account "${SA}" -c . \
  list -q "'""${PARENT_ID}""' in parents" | \
    sed "1d" | grep "${DEST_FILE_NAME}" | head -n 1 | cut -d" " -f1)"

if test -z "${FILE_ID}" ; then
  "${GDRIVE}" --service-account "${SA}"  -c . \
    upload --no-progress --parent "${PARENT_ID}" --name "${DEST_FILE_NAME}" "${SRC_FILE_NAME}"
else
  "${GDRIVE}" --service-account "${SA}"  -c . \
    update --no-progress "${FILE_ID}" --name "${DEST_FILE_NAME}" "${SRC_FILE_NAME}"
fi
$ PARENT_ID="<フォルダーの ID>" DEST_FILE_NAME="Drive 上でのファイル名>" SRC_FILE_NAME="<ローカルのファイル名>" bash ./send.sh
hankei6kmhankei6km

Workload Identitty 連携

GitHub Actions から使いたかったので試してみたが、以下のエラーになる。

Failed getting oauth client: google: read JWT from JSON credentials: 'type' field is "external_account" (expected "service_account")

おそらく https://github.com/golang/oauth2 からのエラーだと思われる。
なんとなくライブラリ側は対応しているように見えるけど Go のビルド環境を整えるのも大変なので Node.js で簡単なツールを作った。

https://github.com/hankei6km/guratan

こちらでは GitHub Actions からもファイルを送信できた。

Google Drive で Slidev の PDF を表示しているスクリーンショット
GitHub Actions で Slidev の PDF をエクスポートしてGoogle Drive へ送信した

https://github.com/hankei6km/test-slidev-export-to-gdrive

hankei6kmhankei6km

少し気になったので auth action が保存したファイルを Google Drive へ送信して確認してみた。
(どれを表に出したらマズいのかわからなかったのでほぼマスクしてある)

サービスアカウントの鍵をダウンロードしたものと様子がかなり違う。

{
  "type": "external_account",
  "audience": "***",
  "subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
  "token_url": "https://sts.googleapis.com/v1/token",
  "service_account_impersonation_url": "***",
  "credential_source": {
    "url": "***",
    "headers": {
      "Authorization": "Bearer ***"
    },
    "format": {
      "type": "json",
      "subject_token_field_name": "value"
    }
  }
}