1
1

GASでAWSリソースにアクセスするために

Posted at

はじめに

とある事情からスプレッドシートをフロントエンドとしてLambdaで処理を行い生成物をGoogle Drive上に保存するシステムを実装する際にすごく悩んだので備忘録として残しておきます。

今回のシステム構成は以下のような構成でした。
image.png

シリアルに処理を実行すると、スプレッドシートの1行を単位で処理するため60分程かかります。
GASの制約としては6分、Lambdaは15分のため何かしら工夫が必要でした。

他のチームメンバだとAPI GatewayでREST API経由で実行したり、S3にファイルを保存したイベントでLambdaを実行していましたが、実行頻度も少ないことと、イベント発火させるためだけにS3にファイルを置くのが無駄だよねということでEventBridge のPutEvents を契機に処理する方針としました。

実績のないこの方針は、AWSナニモワカラナイマンとしてはかなり辛かった。。。orz

GASからAWSリソースへアクセスするために

AWS sdkではいろいろな言語をサポートしていてsdkが使えさえすればACCESS KEY SECRET KEYを作成すれば簡単にアクセスすることができます。

ですが、GASからとなるとAWS sdk がインストールできるわけではないので工夫する必要があります。

GASからAWSへアクセスするのを検索すると何点かヒットします。

最初に試したのがこちら。
https://developer.mamezou-tech.com/blogs/2023/06/28/gas-using-npm-packages/

言っていることはわかる。
でもどのようにGASへ読み込ますなどがピンと来ず断念。

次に試したのがこちら。
https://akkinoc.dev/posts/2022/05/15/aws-api-from-google-apps-script/

使用するのは こちら のGitHub上にあるaws.js というファイルをコピって貼り付けるだけ。
簡単にGASからAWSリソースにアクセスすることができました。
知識を供していただけたこと、素晴らしいスクリプトを公開していただき本当にありがとうございます。

次の課題としては、パラメータをどのように設定するか🤔

aws.jsのパラメータ設定について

上記のページでaws cliをdebugで実行してみるとわかるよということで試してみました。
いきなり最終系ですが、PutEventsを送るには以下のようなGASのコードになります。

  AWS.init(key.accessKey, key.secretKey);

  const obj = {
    Entries: [{
      Source: 'hogehoge',
      DetailType: 'fugafuga',
      Detail: JSON.stringify({
        sheetId : "123456789"
      })
    }]
  };

  const res = AWS.request("events",
                            "ap-northeast-1",
                            "AWSEvents.PutEvents",
                            {},
                            "POST",
                            obj,
                            {"Content-Type": "application/x-amz-json-1.1"});
  console.log(res.getContentText());

ここでの引っかかりポイントは Detail の部分にJavaScriptのオブジェクトをそのまま設定しちゃいけないというところです。

Detail 部分にそのままオブジェクトを設定すると、以下のようなエラーが返ってきます。

	{"__type":"SerializationException","Message":"Start of structure or map found where not expected."}

最初、一体どこの部分のことを言っているんだ。。。?と。
ユーザガイド を何回も読みふと気がついたことで、Detail をよく見るとjsonオブジェクトじゃなく文字列になっているじゃんと。

ということで Detail をstringifyして設定することで無事イベント登録することができました。
成功すると、以下のようなログが出力されます。

{"Entries":[{"EventId":"079ceaa5-b673-aecd-c815-b6202c2edf8e"}],"FailedEntryCount":0}

EventBridgeとStep Functions をつなぐために

イベントは正しく登録できたっぽい。
ただし、EventBridgeのモニタリングにもCloudWatch Logsにも何も出てこない。
ホントに正しく登録できているのか。。。🤔というのに3日位悩みました。
ログ的なものは何も残ってないけど、APIKEYの Last used は変わっているのでAWSの世界には来てるんだろうと信じて、とりあえずつなぐ部分を進めてみました。

まずはEventBridgeでルールを作ろう。
ここは問題ないだろう。
image.png

ひっかかったのは次のページ。
イベントソースはAWSのイベントを契機にするので一番上でOK。
次のSample event はoptional と書いてあるので無視。
image.png

ここからがよく分からなかった。
今回はEventBridge のPutEvents を設定したいのに表示されない。
image.png

とりあえず All Events にすれば良いのかと選択すると、以下のようなパターンが設定される。
image.png

この source というのはどこのことを指しているんだ。。。🤔とモヤモヤしつつ進め、ターゲットにStep Functions を設定。
image.png

これでルールができたのでGASから実行してもStep FunctionsのExecutionsのところにイベントが増えない。
※ 以下の画像はすでに繋がっているためいっぱいあります
image.png

イベントに登録できているのにルールに引っかかっていないためイベントが破棄されてそう。
イベントパターンに全部のイベント引っかかるようにしているはずなのになぜ?というところで悩みまくっていました。

色々考えた挙げ句、イベントパターンの部分をよくよく見てみると Prefix matching とかいくつかあります。
もしかしてさっき source の部分に [aws.events]とか設定したけど、これ自体がGASで設定しているオブジェクトの Entries のフィルタなのでは?思いつきやってみたところビンゴ。
image.png

完全一致ではないのね。。。と思いつつなんとか繋がってホッとしました。

おわりに

これでGASからの連携でAPI Gatewayを建てなくても良いし、無駄にS3にファイルを置かなくてもPOSTのパラメータだけでAWSリソースにアクセスすることができました。

自分なりに色々探してみたけどみんな普通はどうやるんだろう。。。という部分はモヤモヤしたままですが、目的を達成できてとりあえず満足。

ここまでお付き合いしていただきありがとうございます。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1