Slackで寿司を回転させる技術

こんなツイートをしたらいいねが1000件以上ついたのでやり方を紹介します。

きっかけ

以前Slackで絵文字を回転させる方法を紹介しましたが、もっとちゃんと寿司を回転させたくなりました。

kurochan-note.hatenablog.jp

画像生成

今回もImage Magickを使います。Mac上で生成しました。

絵文字を3行3列の9個順番に並べるといい感じに回っているように見えるのですが、中心は冒頭で紹介した記事で絵文字を回転させてください。今回は中心以外の8種類の画像を生成します。

出来上がったものはこちらです。

f:id:kuro_m88:20170918183136g:plainf:id:kuro_m88:20170918183152g:plainf:id:kuro_m88:20170918183156g:plainf:id:kuro_m88:20170918183202g:plainf:id:kuro_m88:20170918183210g:plainf:id:kuro_m88:20170918183214g:plainf:id:kuro_m88:20170918183218g:plainf:id:kuro_m88:20170918183221g:plain

スクリプトはこんな感じです。最後のgifアニメ生成時の -colors 80 -fuzz 11% というオプションはSlackの絵文字のファイルサイズの64KB制限に引っかからないように画質を手でパラメータ調整した結果です。もしオーバーするようであれば値をいじってみてください。

gist.github.com

もちろん寿司以外にも使えます。いろんな絵文字を回していきましょう。寿司を静止させられるように明日から頑張ります。

DataDogの監視設定からTerraformのresourceを生成する

作ったものはこれ。

github.com

やりたいこと

TerraformのDataDog Providerを使って監視ルールをTerraformで管理したい。resource定義さえ書けば監視ルールがTerraformで管理されるようになります。 参考: Datadog: datadog_monitor - Terraform by HashiCorp

ただ、 query = "avg(last_1h):avg:aws.ec2.cpu{environment:foo,host:foo} by {host} > 2" のようなクエリを書くのは厳しいので、テンプレート化する前はDataDogのWeb UIでルールを作成したいですよね。 そこで既存の監視設定を取り込んでTerraformの設定を生成するようにしました。

Terraform importとどう違うのか

Terraformには terrafrom import という便利なコマンドがあり、既存のterraform管理されていないリソースをterraform管理下に置くことができます。しかしながら、以下の記事にも書いてあるとおり、 tfstate ファイルに状態として取り込まれるだけで、 設定を/構成を管理する tf ファイルには反映されません。

dev.classmethod.jp

使い方

詳細はREADMEに書きました。

datadog_monitor2terraform/README.md at master · kurochan/datadog_monitor2terraform · GitHub

ただのrubyスクリプトなので

$ ruby ./monitor-import.rb dynamodb_user_error_count 112233

resource "datadog_monitor" "dynamodb_user_error_count" {
  name               = "DynamoDB UserError count is above the Threshold !!"
  type               = "metric alert"
  message            = <<EOF
@slack-metric-alert DynamoDB UserError count is above the Threshold !!
EOF
  query = "sum(last_5m):sum:aws.dynamodb.user_errors{*} > 10"
  thresholds {
    warning = 5.0
    critical = 10.0
  }
  notify_no_data = false
  no_data_timeframe = 2
  renotify_interval = 0
  timeout_h = 0
  require_full_window = true
  notify_audit = false
  tags = []
}

という感じで引数にterraformで管理するリソースの名前と、DataDog上での対象のIDを指定するとTerraformのresourceが生成されます。 これで監視ルールの生成と管理が楽にできますね!

Slack用に回転するアニメーション絵文字を作れるようにしてみた

きっかけ

某Slackで回転する :thinking_face: を作っている人がいたので、汎用的に作れるようにしたかった。

f:id:kuro_m88:20170520175648g:plain

↑回転する:thinking_face:

スクリプト

ImageMagickを使ってすぐに生成できるようにしてみた。

#!/bin/bash

WORKDIR=`mktemp -d "tmp-image.XXXXXX"`

input=$1
output=$2

convert ${input} -background white -alpha deactivate -flatten ${WORKDIR}/input.png

for i in `seq -f %02g 0 23`; do
  deg=`expr $i \* 15`
  convert -rotate ${deg} ${WORKDIR}/input.png ${WORKDIR}/img-${i}.png
done

convert -layers Optimize -loop 0 -delay 4 ${WORKDIR}/img-*.png ${output}
rm -rf ${WORKDIR}

透過情報を消してから回転するようにしている。透過情報を消さずに回転すると、前のフレームが残ってしまう模様。

使い方

一つ目の引数に入力ファイル(png)、二つ目の引数に出力ファイル(gif)を指定する。二つ目の引数を .gif にしていないと生成失敗するので注意。

bash emoji_rotate.sh input.png output.gif

f:id:kuro_m88:20170520180008g:plain

↑透過情報を消さずにアニメーション生成するとこんな感じ。

スクリプトの流れとしては、15度ずつ回転させた画像を24枚生成して、それを40msごとに変化させるアニメーションGIFを書き出すようにした。

sbtでJavaプロジェクトを簡単に作るためのテンプレートを作った

sbt new コマンドでJavaプロジェクトがすぐ作れるようにしてみました。

java-seed.g8

作ったものはこれ。

github.com

ほとんどsbt/scala-seed.g8と同じ構成。

github.com

これでもJavaプロジェクトは作れるんですが、Scala用のパッケージがついてきたり、パッケージにバージョンが入ったり、ライブラリ足さないとJUnitが動かなかったりするので、これをベースにちょこっと設定等足した感じです。

使い方

Ubuntu16.04での例です。他の環境でもsbtさえ動けば一緒かなと。ただし、sbt0.13.13以降でしかこの方法は対応していません。

Java, sbtのインストール

ubuntu@c01:~$ echo "deb https://dl.bintray.com/sbt/debian /" | sudo tee -a /etc/apt/sources.list.d/sbt.list
ubuntu@c01:~$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2EE0EA64E40A89B84B2DF73499E82A75642AC823
ubuntu@c01:~$ sudo apt update
ubuntu@c01:~$ sudo apt install openjdk-8-jdk sbt

ubuntu@c01:~$ sbt sbt-version
Getting org.scala-sbt sbt 0.13.13 ...
downloading https://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/sbt/0.13.13/jars/sbt.jar ...
        [SUCCESSFUL ] org.scala-sbt#sbt;0.13.13!sbt.jar (3942ms)
downloading https://repo1.maven.org/maven2/org/scala-lang/scala-library/2.10.6/scala-library-2.10.6.jar ...
(省略...)
[info] Set current project to ubuntu (in build file:/home/ubuntu/)
[info] 0.13.13

sbtコマンドを初めて打った時だけ初期化に時間がかかりますが、我慢。

他の環境でのセットアップ方法はこちら。 sbt Reference Manual — sbt のインストール

sbtでJavaプロジェクトを作る

プロジェクトを作りたいディレクトリで、 sbt new kurochan/java-seed.g8 を実行。 kurochan/java-seed.g8Javaプロジェクトのテンプレート。他にも色々テンプレートがあります。

giter8 templates · foundweekends/giter8 Wiki · GitHub

こちらも省略だけ少し時間が掛かりますが待ちましょう。

ubuntu@c01:~$ sbt new kurochan/java-seed.g8
[info] Set current project to ubuntu (in build file:/home/ubuntu/)
[info] Resolving com.github.scopt#scopt_2.10;3.5.0 ...
[info] downloading https://repo1.maven.org/maven2/org/scala-sbt/sbt-giter8-resolver/sbt-giter8-resolver_2.10/0.1.0/sbt-giter8-resolver_2.10-0.1.0.jar ...

(省略…)

Minimum Scala build.

name [My Something Project]: java-project-sample

Template applied in ./java-project-sample

生成されたプロジェクト

これでベースのプロジェクトの生成ができました。プロジェクトのファイル構成はこんな感じ。

build.sbtとprojectディレクトリ以下がビルド設定で、srcディレクトリ以下がアプリケーションのコードです。

ubuntu@c01:~$ cd java-project-sample/
ubuntu@c01:~/java-project-sample$ tree -a -L 5
.
├── build.sbt
├── .gitignore
├── project
│   ├── build.properties
│   └── Dependencies.scala
└── src
    ├── main
    │   └── java
    │       └── example
    │           └── Hello.java
    └── test
        └── java
            └── example
                └── HelloTest.java

コンパイルする

プロジェクトのルートディレクトリでsbtを起動して、compileコマンドを打つ。 sbt compileと打つとsbtのコンソールに入らずに直接コンパイルできます。

ubuntu@c01:~/java-project-sample$ sbt
[info] Loading project definition from /home/ubuntu/java-project-sample/project
[info] Updating {file:/home/ubuntu/java-project-sample/project/}java-project-sample-build...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Compiling 1 Scala source to /home/ubuntu/java-project-sample/project/target/scala-2.10/sbt-0.13/classes...
[info] 'compiler-interface' not yet compiled for Scala 2.10.6. Compiling...
[info]   Compilation completed in 9.911 s
[info] Set current project to Hello (in build file:/home/ubuntu/java-project-sample/)
> compile
[info] Updating {file:/home/ubuntu/java-project-sample/}root...
[info] Resolving org.sonatype.oss#oss-parent;9 ...
[info] downloading https://repo1.maven.org/maven2/junit/junit/4.12/junit-4.12.jar ...
(省略…)
[info] Compiling 1 Java source to /home/ubuntu/java-project-sample/target/classes...
[success] Total time: 14 s, completed Mar 25, 2017 10:47:58 AM
>
>
> compile
[success] Total time: 0 s, completed Mar 25, 2017 10:48:12 AM
>

差分コンパイルが効いているのでコードに変更を加えずに2回目に compile と打っても一瞬で終わる。テストコードを含めて全部コンパイルするときはcompileの代わりにtest:compileと打ちましょう。

ソースコードの変更を検知してコンパイル

毎回compileと打たなくてもソースコードが書き換わったのを監視して差分コンパイルしてくれる機能もあって ~compile と頭にチルダをつけるだけ。

> ubuntu@c01:~/java-project-sample$ sbt
[info] Loading project definition from /home/ubuntu/java-project-sample/project
[info] Set current project to Hello (in build file:/home/ubuntu/java-project-sample/)
> ~compile
[success] Total time: 0 s, completed Mar 25, 2017 10:51:59 AM
1. Waiting for source changes... (press enter to interrupt)
[info] Compiling 1 Java source to /home/ubuntu/java-project-sample/target/classes...
[success] Total time: 1 s, completed Mar 25, 2017 10:52:43 AM
2. Waiting for source changes... (press enter to interrupt)

実行

run でアプリケーションが起動できる。

ubuntu@c01:~/java-project-sample$ sbt run
[info] Loading project definition from /home/ubuntu/java-project-sample/project
[info] Set current project to Hello (in build file:/home/ubuntu/java-project-sample/)
[info] Running example.Hello
Hello World
[success] Total time: 0 s, completed Mar 25, 2017 10:54:49 AM

テスト

テンプレートプロジェクトにはJUnitのテストケースが書かれていて、それが実行される。

ubuntu@c01:~/java-project-sample$ sbt
[info] Loading project definition from /home/ubuntu/java-project-sample/project
[info] Set current project to Hello (in build file:/home/ubuntu/java-project-sample/)
> test
[info] Compiling 1 Java source to /home/ubuntu/java-project-sample/target/test-classes...
[info] Passed: Total 2, Failed 0, Errors 0, Passed 2
[success] Total time: 1 s, completed Mar 25, 2017 10:55:53 AM
>
>
> test
[info] Passed: Total 2, Failed 0, Errors 0, Passed 2
[success] Total time: 0 s, completed Mar 25, 2017 10:56:03 AM

こちらはコンパイルの時と違って、コマンドを打ったら全部テストが走る。

差分テスト

変更があったクラスのテストだけ実行するには testQuick と打ちます。

ubuntu@c01:~/java-project-sample$ sbt
[info] Loading project definition from /home/ubuntu/java-project-sample/project
[info] Set current project to Hello (in build file:/home/ubuntu/java-project-sample/)
> testQuick
[info] Passed: Total 0, Failed 0, Errors 0, Passed 0
[info] No tests to run for test:testQuick
[success] Total time: 0 s, completed Mar 25, 2017 11:00:07 AM

差分がなければテストは走らない。 ~testQuick と頭にチルダをつけておけば、ソースコードの変更を監視して、必要なテストだけ走るのでローカルで開発するときに便利。

REPL機能

ScalaのREPLですが、ビルドしたアプリケーションのクラスを呼び出したりできます。補完も効く。

ubuntu@c01:~/java-project-sample$ sbt
[info] Loading project definition from /home/ubuntu/java-project-sample/project
[info] Set current project to Hello (in build file:/home/ubuntu/java-project-sample/)
> console
[info] 'compiler-interface' not yet compiled for Scala 2.12.1. Compiling...
[info]   Compilation completed in 12.547 s
[info] Starting scala interpreter...
[info]
Welcome to Scala 2.12.1 (OpenJDK 64-Bit Server VM, Java 1.8.0_121).
Type in expressions for evaluation. Or try :help.

scala> import example.Hello
import example.Hello

scala> Hello.main(Array())
Hello World!

scala> Hello.
echo   join   main

scala> Hello.join("hoge", "fuga")
res2: String = hogefuga

他にも便利な機能はたくさんあるのでJavaプロジェクトでもsbtは結構使えるんじゃないかなぁと。

sbt Reference Manual — 始める sbt