GAE版goslashサンプルで開発モードを実装してみる
goslashのサンプルをちょっと変えてみて、GAEをローカルで動かした時にデバッグしやすい修正をしてみました。
まぁGAE使っている人は知っているよ、という内容だと思います。
やりたいこと
goslashでは、Pluginを呼び出した際にSlackから渡されたresponse_url
に対してレスポンスをPOSTします。
ただし、ローカルで動かした場合にはSlackから呼び出されるわけではないため、response_url
は存在しないこともあります。
このような場合にPluginのデバッグを行うために、ローカルで動かした場合にはリクエストのレスポンスとして、送信内容を返すようにしてみたいと思います。
どうやったか
具体的なコードは以下のようになります(一部)
if appengine.IsDevAppServer() { // (1) 開発用サーバの場合 cmd, _ := req.CmdArgs() p, ok := slashPlugins[cmd] if !ok { renderer.JSON(w, http.StatusNotFound, "cmd not found") return } // (2) リクエストに対するPluginの実行結果をJSONにしてレスポンスとして返す msg := p.Do(req) var jsonData bytes.Buffer if err := json.NewEncoder(&jsonData).Encode(&msg); err != nil { renderer.JSON(w, http.StatusInternalServerError, err.Error()) return } renderer.JSON(w, http.StatusOK, jsonData.String()) } else { // (3) 本番環境の場合 renderer.Text(w, http.StatusOK, slashCmd.Execute(req)) }
(1) 開発用サーバの判定
開発サーバかどうかは、appengineのIsDevAppServer()
APIで判定できます。
この条件が真になった場合には、呼び出し元にレスポンスとして返す処理を実行します。
(2) リクエストに対するPluginの実行結果をJSONにしてレスポンスとして返す
ここのp
はそれぞれのPluginの実装になります。
Do
メソッドで、リクエストに対する個々のメッセージを作成します。
作成したメッセージはJSONデータとしてエンコードし、リクエストに対するレスポンスとして呼び出し元に返します。
(3) 本番環境の場合
もとのサンプルと同様の処理を実装しています。
動かしてみる
curlで実行した結果は次のようになりました。
$ curl -X POST -d "text=time" http://localhost:8080/v1/cmd
"{\"response_type\":\"in_channel\",\"text\":\"2016-08-08T16:31:26Z\"}\n"
ちょっとしたPluginの確認ならば、簡単にできますね。
具体的なコードは、この辺に置いときます。 https://github.com/yhanada/goslash-sample-gae
slack-slash-commandを試す
GAEやGoを使ってやりたかったことは、Slackのインテグレーションです。
昨日まででGAEをIntelliJ IDEAで動かすところまでは出来ました。 これからは、 GAE/GoでSlackの'/'(スラッシュ)コマンドサーバーを立てる
をきっかけに、
- GAE/GoでSlackのSlach Commandを実現する
- IntelliJ IDEAで開発しやすい環境を作る
- 新しいPluginを作ってみる
ということを目指していきます。
さて、kyokomiさんは、SlackのSlash CommandだけではなくてBotのフレームワークslackbotも公開されています。 ゆくゆくはクラウド環境で動くSlackBotも作ってみたいですね。
さて、肝心のslack slack commandは、上記のQiitaの通りにやってみるとあっさり動きました。
素晴らしいです!!
IntelliJ IDEAでGoogle App Engine for Goの環境を設定する
昨日はコマンドプロンプトでGoogle App Engine for Goのサンプルを起動するまで確認できました。
きっかけ
実は個人でJetbrainsのツールのライセンスを持っており、普段の仕事でもプライベートでも大活躍しています。 ということからIntelliJ IDEAでGAE for Goの環境を作ってみたいと思います。
どうやったか
JetbrainsのツールプラグインとしてGoものはだいぶ前からあるのですが、設定がよくわからなくて最初迷いました。
SDKの設定
通常のGoも入れているため、GoのSDK設定は完了しています。 しかしこのままではGAE for Goのプロジェクトは起動できません。
いろいろとググってみたところ、GoのSDKとしてGAE for Goを指定すれば良いということがわかりました。
SDKの場所として昨日いれた~/go_appengine
を指定します。
SDKの登録ができたら、プロジェクトで使用するSDKとしてこちらを指定します。
実行するで
よっしゃこれでいけるわ、と思ったもののうまく起動できず。
EditConfigurationsでもモジュールがないぞー
と言われる始末。
昨日の環境では、プロジェクト直下にhello.go
がおいてあったのですが、それがまずかったようです。
こんな感じで、プロジェクト配下にhello
というディレクトリを作り、その下にgoファイルを置くとモジュールとして登録できるようになりました。
ちなみにモジュール単位でSDKを選択できるらしいので、通常のGo SDKではなくてGAE for GoのSDKを指定するようにしましょう。
これでEdit Configurationsでも登録できて、Run
の実行でローカルでの起動ができるようになりました。
メデタシメデタシ
Google App Engine for Goの環境を作る
きっかけ
流行りに乗ってBot作りたい。というのが理由。 Herokuとかが多そうだけど、Goを使ってとなるとGoogle App Engine(GAE)でもいいんじゃないかと思ったので、勉強も兼ねて環境を作ってみる。
インストール
まずは、SDKを入れる。 Quick StartページからSDKをダウンロードして適当な場所に置きます。
今回は、HOMEの下に置きました。
~/go_appengine
どうもpython 2.7が必要らしいけど、もともと入っていたもので良さそう。
$PATH
を通してこれで準備完了。
サンプルを起動
QuickStartページにサンプルの動かし方があるので、順番にやってみる。
リポジトリのclone
サンプルのリポジトリがGitHubにあるので、てけとうな場所にcloneします。
$ cd てけとうな場所 $ git clone -b part1-helloworld https://github.com/GoogleCloudPlatform/appengine-guestbook-go.git helloworld $ cd helloworld
いまは、helloworld
いいるのでこの場所で先ほどインストールしたSDKの下のgoapp
コマンドを以下のように呼び出します。
goapp serve .
初回起動時だけCould not read search indexesと言われますが、普通に起動します。
コンソールにも表示されていますが、3つのサーバが公開されています。
- http://localhost:8080
- 本体
- http://localhost:8000
- Admin サーバ
- http://localhost:56950
- API サーバ
起動しているサービスを終了させるには、Ctrl-Cを押下する必要があります。
Adminサーバでは、GAEが提供するDataStoreやmemcacheなどの内容を確認したりできるため、デバッグなどで役に立ちそうです。
App Engineにデプロイする
まずは、Cloud Platform Consoleにログインし、プロジェクトを作成します。 作成したら、Project IDを控えておいて、次のようにターミナルで実行します。
$ appcfg.py -A <ProjectID> -V v1 update .
これを実行するとデフォルトブラウザが開いて、Googleアカウントの認証処理が走ります。 ここで利用するアカウントの選択を行い、ターミナルに戻るとゴロゴロと処理が走っていることが確認できます。
Authentication successful. 01:35 AM Scanning files on local disk. 01:35 AM Cloning 4 application files. 01:35 AM Compilation starting. 01:35 AM Compilation: 1 files left. 01:35 AM Compilation completed. 01:35 AM Starting deployment. 01:35 AM Checking if deployment succeeded. 01:35 AM Deployment successful. 01:35 AM Checking if updated app version is serving. 01:35 AM Completed update of app: <ProjectID>, version: v1
上記のようにターミナルには表示されました。無事にデプロイされたようです。 このプロジェクトのURLは、次のようになります。
http://<ProjectID>.appspot.com
さらに、httpsでもアクセスできますので、セキュアなAPIも簡単に用意できますね。
プロジェクトの削除
さくさくドキュメントを読み進めていくと、「Clean upのやりかた」とか書いてますね。 リソースの状況によってはお金がかかるのを避けるために不要なプロジェクトは消しましょう。
Cloud Platform Consoleから「すべてのプロジェクトの管理」ページに遷移し、削除したいプロジェクトにチェックを入れ、右上のゴミ箱ボタンをクリックします。 これでサービスはシャットダウンされますが、すぐに削除はされないようで、しばらくは復元させることができるようです。 うっかりさんには安心ですね。
どこまで遊び倒せるか
App Engineの料金ページを見ると、課金を有効にしないかぎりはお金は掛からないようです。 ただし、上限を超えた場合には503エラーが発生します。
また、課金を有効にした場合でも一日あたりの予算を設定することが出来ます。小さなサービスで開始し、大きく成長させる場合や、ちょっとお試しの場合にも使いやすいですね。
ということで、ドキュメントの読み込みから始めるかな。
DockerでMySQL、PHP、Apacheを連携させる
きっかけ
MySQLサーバのTimeZoneがUTCで、アプリケーションのTimeZoneがAsia/Tokyoの場合に、実際のところどうなるか確認したかった。
ということでDockerの勉強も兼ねてMySQLとPHP/Apacheの2種類のイメージを連携させる方法を調べたのでメモります。
いつものように先人の知恵はこちら
今回使ったイメージは公式のイメージを利用しています。
- mysql:5.7
- php:5.6-apache
- 今回はこれをベースにPDO MySQLを追加した
MySQLサーバ起動
上記の公式イメージを取得し、ローカルでコンテナ起動
$ docker pull mysql:5.7 $ docker run --name mysqld -e MYSQL_ROOT_PASSWORD=pass -d mysql:5.7
ここでは、ROOTのパスワードを指定しています。 パスワード以外にもいろいろと指定できますので、本格的なWebアプリケーション用に構築するならばDocker Hubや参考サイトを確認してください。
MySQLクライアントの起動
同じイメージにはMySQLのクライアントも入っているので、別のコンテナとして起動します。 --linkオプションを付けることで、先ほど起動したmysqldと連携させることが出来ます。
$ docker run --link mysqld:mysql -it --rm mysql /bin/bash
MySQLクライアントからMySQLサーバに接続
Dockerのコンテナに入れたら以下のコマンドでMySQLサーバに接続できます。
# mysql -u root -ppass -h $MYSQL_PORT_3306_TCP_ADDR
$MYSQL_で始まる環境変数は他にも定義されいますので、env
コマンドなどで確認してください。
接続できたら、てけとうなDBとテーブルを作ります。
CREATE DATABASE mydb; USE mydb; CREATE TABLE users( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(32), created TIMESTAMP ); INSERT INTO users(name, created) VALUES('山田', NOW());
PHPのイメージ準備
公式のphp:5.6-apacheをベースにして、PDO MySQLを追加インストールしたイメージを作成します。
FROM php:5.6-apache RUN apt-get update && \ docker-php-ext-install pdo_mysql
これをベースにイメージをビルドします
$ docker build -t php:5.6-apache-pdo-mysql .
PHPコンテナ起動
PHPのイメージがビルドできたら、適当なディレクトリをマウントして起動します。 今回はApacheが同梱されたイメージですが、PHPのCLIを使って確認します。
$ docker run --link mysqld:mysql -it --rm -v `pwd`:/var/www/html php:5.6-apache-pdo-mysql /bin/bash
UTCのMySQLとAsia/TokyoのPHPプログラムの変換
次のようなプログラムで確認してみました。
実行すると1レコードINSERTします。created
にはNOW()
で値を入れているためUTCでの時刻として表示されます。
なので、$row['created']
は、UTCでの日時表記となっています。
このサンプルではDateTime
クラスを使ってUTCからAsia/Tokyoへの変換を行っています。
<?php // default timezone=Asia/Tokyo date_default_timezone_set('Asia/Tokyo'); // connect DB $db = new PDO('mysql:host=mysql;dbname=mydb', 'root', 'pass'); // sample record $db->query("INSERT INTO users(name,created) VALUES('ほげほげ', NOW())"); $st = $db->query("SELECT * FROM users"); $rows = $st->fetchAll(); foreach ($rows as $row) { $user = []; $user['name'] = $row['name']; // retrieve as UTC $dt = new DateTime($rows['created'], new DateTimeZone('UTC')); // set default timezone $dt->setTimeZone(new DateTimeZone(date_default_timezone_get())); $user['created'] = $dt->format('Y-m-d H:i:s'); var_dump($user); }
PHPから値を入れる際には、一工夫必要になる気がしますが、それは今後のお話で。
SSHのPAM認証をHookしてLinuxサーバへのログインをSlackに通知する
久しぶりに書こうと思ったら、何か別のブログを開設してしまった。 いい機会なので、Markdown形式で書くことにします。
今回のネタは、個人のサーバをさくらの専用サーバからIDCFのクラウドに移行したことと、いろいろな通知をSlackに出してみようと思ったことから始まってます。
きっかけ
Slackで遊びたいと思っていろいろ調べたところ、IDCFの踏台サーバにログインした通知を出せることがわかったので、その辺りについて書いてみます。 といってもググってみればわかることだけど。
どうやるか
Google Cloud Platform で Slack との連携を実現する 3 つの方法に書いてある、notify
のサンプルを使う。
これは、PAMフックを利用してSSHでログインしたことを検知し、SlackのWebHook APIに対してPOSTするものです。
他にもnode.jsを使う方法や、.ssh/rc
を使う方法がありましたが、
- 踏台なのでなるべく余計なものは入れたくない(踏台サーバはIDCFのS1を使っているため)
- アカウントごとに設定が必要な物は避けたい
ということから、このPAMフックによる通知を選択しました。
ただし、PAMフックを使うにはsshdの設定で使えるようにしなければなりません。
IDCFで使っている踏台はCentOS7テンプレートから作ったので初期設定を確認したところ、/etc/sshd_config
にはデフォルトでusePAM yes
となっていました。
ということで、特に悩まずにシェルスクリプトをインストールできました。
まとめ
Slack便利