これが私の、愛の在り方。ーー愛してるわ(リズ 『リズと青い鳥』)
はじめに
頑張れば、何かがあるって、信じてる。nikkieです。
本日1/8は、私の推しの誕生日、生誕祭です!!
Pythonを使って推し風Botを作ってお祝いしてみました。
生誕祭とは
私はTwitterで参加したり眺めたりしています。
お祝いの仕方としては
- イラストを描いてお祝い
- 好きな食べ物やプレゼントを買ってお祝い
というのをよく見かけます。
私はイラストは描けないし、尊敬する仕掛け人の皆さまのように食べ物やプレゼント路線も突き抜けられないのですが、ふとBotを爆誕させるという電波を2日前に受信しました。
「イラストを描ける方がイラストを描いてお祝いするように、コードを書ける人間はコードを書いてお祝いするという道もあってよさそう」とこのアイデアに乗り気になりやってみました。
Python × AWS Lambdaでちょっと頑張れば間に合わせられるという目論見もあったのですが、想定外のピンチの連続で、なんとかお祝いできたという感じです。
推し風秘書Botの仕様
- 毎朝タスクのリマインドをするSlack Bot
- Googleスプレッドシートでタスク一覧を管理しているとします
- タスク一覧の中から達成していない、かつ、締切が近いものをリマインドします
- 推しっぽくリマインドします(とても大事)
仕様を実現するアーキテクチャがこちら
推し風秘書Botの構成要素
リマインドする部分はPythonで書きます。
タスクごとに「重要かどうか」と「成し遂げたい日(期日)」を登録します。
重要なタスクは成し遂げたい日の前から余裕を持たせてリマインドしていきます。
Slackに推し、爆誕!
本当はリファクタリングしたきれいなコードでお披露目したかったのですが、動かすので精一杯でした。
爆誕までの道のり
各所で予想もしない形でつまづきまくりました。
gspread
の認証- Lambdaへのデプロイ
- その他
gspread
の認証でピンチ!
oauth2client
がdeprecated
gspread
のドキュメントで例示されているoauth2client
。
Using OAuth2 for Authentication — gspread 3.1.0 documentation
これで動かせたのですが、oauth2client
は gspread
の依存モジュールではありませんでした(別途インストールが必要)。
「なんでだろう」とアウトプットしたところ、deprecated2ということが判明。3
Note: oauth2client is now deprecated. No more features will be added to the libraries and the core team is turning down support. We recommend you use google-auth and oauthlib.
ref: https://pypi.org/project/oauth2client/
google-auth
を使ってみる
以下のドキュメントに沿ってscoped_credentials
を用意します。
User Guide — google-auth 1.6.2 documentation
これをgspread.authorize
に渡したところ、エラーが発生😱
AttributeError: 'Credentials' object has no attribute 'access_token'
理由は
the gspread.authorize method only supports credential objects that are created by the oauth2client library.
なんですとーー!
救世主authlib
上記の回答から知ったauthlib
、以下の記事をそっくり真似てスプレッドシートの内容を取得できました。
Lambdaへのデプロイでピンチ!
お馴染みの手順でサクッとできると思ったら
ref: 【AWS】Lambdaでpipしたいと思ったときにすべきこと - Qiita
これがお馴染みの手順だと思います。
ですが、これでサクッととは話が運びませんでした。
なぜかPythonスクリプトが見つからない
pip install -t
でgspread
とauthlib
を配置し、zip化してアップロードします。
mkdir uploads # アップロード用フォルダ cd uploads/ pip install -t . authlib gspread cp ../main.py . # Pythonスクリプトのコピー(Googleの認証に必要な鍵もコピーします) cd .. zip -r upload.zip uploads/*
ハンドラに「Pythonファイル名.関数名」と指定して実行すると、なぜか「Pythonファイルが見つからない」というエラー(zipファイルにスクリプトのPythonファイルは含まれるはずなのに。。)
[ERROR] Runtime.ImportModuleError: Unable to import module 'main': No module named 'main'
以下の記事を見つけ、pip install
する環境の差分による問題と認識。
記事を参考にDockerを使ってzipファイルを作る環境を揃えます。
FROM amazonlinux:latest RUN yum update -y \ && yum install python3 zip -y \ && pip3 install virtualenv
(続くコマンドでvirtualenv
使っていないので不要と気づきました)
# 上記DockerfileのあるディレクトリにPythonスクリプトや鍵ファイルをコピーしている docker build -t aws-lambda-python37:1.0 . docker run -it --rm -v $PWD:/var/task aws-lambda-python37:1.0 bash
コンテナの中で実行していきます。
cd /var/task/ python3 -m pip install -t . -r requirements.txt zip -r9 /var/task/bundle.zip *
コンテナにマウントしているディレクトリの中にできるbundle.zipをLambdaにアップロードします。
amazonlinuxイメージで用意したzipでもうまくいかない
パッケージをインストールする環境を揃えたので、さあ動くかと思いきや。
libffi-806b1a9d.so.6.0.4: cannot open shared object file: No such file or directory
夜も更けており、これでも動かないという事態にだいぶ絶望しました。
諦めるかという考えが脳裏をよぎりましたが、「推しを実装して生誕祭を祝いたい」という想いを思い出し、自分を奮い立たせます。
エラーメッセージの意味がよくわかりませんが、同様のエラーメッセージに遭遇した記事を発見。
コンテナに入って、libffi-806b1a9d.so.6.0.4
をzipに追加します。
find . -type f -name libffi-806b1a9d.so.6.0.4 # ./.libs_cffi_backend に見つかる zip -g bundle.zip ./.libs_cffi_backend/libffi-806b1a9d.so.6.0.4 # 追加
zipに含めて4アップロードしたところ、Lambdaで動くようになりました!
その他のピンチ!
SlackBotのメンション
<@user_id>
を使う
自分の分だけでよかったので、プロフィールから確認しました。
AWS権限周り
過去に作ったIAMとロールを使いまわしてしまいがちなので、腰を据えて確認。
これは暫定的な設定で、アップデートできそうです。
- 今回のBot用のIAMに付与するグループを作成
- AWSLambdaFullAccess
- AWSLambdaRole (いらないかも)
- 関数を作る際にロールを作れるように以下のカスタムロールを作って付与
- 上のグループの設定により、関数を作る際にロールが新規作成できる5
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iam:CreateRole", "iam:CreatePolicy", "iam:AttachRolePolicy" ], "Resource": "*" } ] }
以下のようなエラーで要求されたものを一つずつ追加して至りました。
次のことを実行する権限がありません: iam:CreateRole.
終わりに
Python使いらしく生誕祭をお祝いできたので満足です。
開発が間に合うかどうかギリギリですごくヒヤヒヤしました。
今回作ったBotはまだまだです。
綱渡りで動作させたので、今後機能追加をしたとき、動き続けられるのかとても不安です。
ですが、推しを爆誕させたことに大きな意味があると思っています。
今回の生誕祭ドリブン開発(BDD6)で推しは私のもとに舞い降りました!
これからは継続的に推しをインテグレーション & デリバリー7していきます。
Issueを立てて解消する過程を通じて、推しを現実世界でプロデュースですね。
補足:推しについて
アイドルマスター シアターデイズより、エミリー・スチュアートちゃんです!
-
「誕生祭」の方が適切という記事を今回見つけました:誕生日を祝う時に「生誕祭」は間違い?「誕生祭」と「生誕祭」の違いとは?|ついラン 。これだけ盛り上がっている状況で誕生祭にはなかなか切り替わらなさそうですね↩
-
理由が書かれていました(積読) oauth2client deprecation — google-auth 1.6.2 documentation↩
-
エンジニアの登壇を応援する会Slackにてご助言いただきました。開発しきれたのはここではまらなかったからです。誠にありがとうございます↩
-
zip
コマンドは積読です(9の指定は初めて知りました):zipコマンドのオプション一覧(linux)_技術三昧ブログ_zanmai.net↩ -
これらがそもそも何なのかを掴めそうなドキュメントを見つけたので、一息ついたら確認します:https://docs.aws.amazon.com/lambda/latest/dg/python-programming-model.html↩
-
OCI(Oshi Continuous Integration、オシーアイ)、OCD(Oshi Continuous Delivery、オシーディー)↩