Add annotation to Mackerel when changed infrastructure with Terraform
mackerelにグラフアノテーション機能が追加されました。
- グラフアノテーションをリリースしました! ほか - Mackerel ブログ #mackerelio
- Mackerel API ドキュメント(v0) - Mackerel API ドキュメント (v0)
グラフアノテーション機能とは先日のmackerelミートアップでも紹介があった通り、デプロイや何かしらの事象をmackerelのグラフ上で注釈することができる機能です。
今回はterraformで特定のリソースに変更があった場合、それをグラフ上に表示させてみます。
まずは普通にAPIを叩いてみる
鬼のようなcurlを実行します。
できた。
Terraformと連携させる方法を考える
今回は例として、DigitalOceanのtagリソースに変更が加えられた場合、グラフに注釈を入れるようにしてみます。
「tagリソースに変更が加えられた場合何かを実行する」方法として、null_resourceとlocal-execを使ってみます。
local-exec
とはterraformの提供するprovisionersの一つで、その名の通り何かしらのリソースと連携させて、ローカル上(terraformコマンドを実行するマシン上)でコマンドを実行するプロビジョナです。
例えば公式のドキュメントではEC2インスタンスが立ち上がった後インスタンスのipアドレスをechoする例を挙げています。
resource "aws_instance" "web" {
...
provisioner "local-exec" {
command = "echo ${aws_instance.web.private_ip} >> private_ips.txt"
}
}
null_resource
とはどのリソースにも(例えばaws_instance
など)関連付けずにプロビジョナを実行したい場合に使われるものです。ではどのタイミングでプロビジョナが実行されるかというと、
null_resource
自体に変更が加わったとき(名前を変えたりとか)triggers
で指定したリソースのアトリビュートに変更が加えられたとき
に発動します。
つまり、今回は「null_resourceのtriggersにtagリソースを指定」して「null_resourceにlocal-execを組み込む」ことで「tagリソースに変更が加えられたらグラフに注釈を入れるコマンドを実行する」ことができそうです。
やってみる
以下のコードをmain.tfに追記してみました。
vault_generic_secret
データソースを使いvaultからmackerelのapiキーを取得null_resource
のtriggersにタグリソースの変数をmodule越しに指定null_resource
にlocal-exec
を所属させ、鬼のようなcurlを実行
data "vault_generic_secret" "mackerel_apikey" {
path = "secret/mackerel_apikey"
}
resource "null_resource" "tag_changed_annotation" {
triggers {
value = "${module.droplet.tag_name}"
}
provisioner "local-exec" {
command = "curl -X POST -H \"X-Api-Key: ${data.vault_generic_secret.mackerel_apikey.data["value"]}\" -H \"Content-Type:application/json\" -d \"{\\\"title\\\": \\\"terraform\\\", \\\"description\\\": \\\"Tag changed\\\", \\\"from\\\": $(date +%s), \\\"to\\\": $(date +%s), \\\"service\\\": \\\"VPS\\\", \\\"roles\\\": [\\\"ponpokopon\\\"]}\" https://mackerel.io/api/v0/graph-annotations"
}
}
${data.vault_generic_secret.mackerel_apikey.data["value"]}
の部分でmackerelのapiキーをセットしています。最近マイブームなvaultプロバイダを使用しています。
Applyしてみる
tagを書き換えて...。
# Create tag
resource "digitalocean_tag" "ponpokopon" {
- name = "ponpokopon2"
+ name = "hogehoge"
}
terraform apply実行!
$ terraform apply
...
null_resource.tag_changed_annotation (local-exec): Executing: /bin/sh -c "curl -X POST -H "X-Api-Key: XXXXXXXX" -H "Content-Type:application/json" -d "{\"title\": \"terraform\", \"description\": \"Tag changed\", \"from\": $(date +%s), \"to\": $(date +%s), \"service\": \"VPS\", \"roles\": [\"ponpokopon\"]}" https://mackerel.io/api/v0/graph-annotations"
null_resource.tag_changed_annotation (local-exec): % Total % Received % Xferd Average Speed Time Time Time Current
null_resource.tag_changed_annotation (local-exec): Dload Upload Total Spent Left Speed
null_resource.tag_changed_annotation (local-exec): 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
null_resource.tag_changed_annotation (local-exec): 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
null_resource.tag_changed_annotation (local-exec): 100 274 100 141 100 133 209 197 --:--:-- --:--:-- --:--:-- 209
null_resource.tag_changed_annotation (local-exec): {"id":"2VaicFLCaTN","title":"terraform","description":"Tag changed","from":1485687817,"to":1485687817,"service":"VPS","roles":["ponpokopon"]}
...
良さそう!グラフ確認。
Yay!!
課題
- 全てのリソースを対象に変更を検知し、
local-exec
を適用したい - 下記エラーが出る事がある
null_resource.tag_changed_annotation: Destruction complete
Error applying plan:
1 error(s) occurred:
* digitalocean_tag.ponpokopon: Failed to update tag: PUT https://api.digitalocean.com/v2/tags/ponpokopon2: 422 Error processing request: operation failed. Please try again.
module.droplet.digitalocean_tag.ponpokopon: Creation complete
Error applying plan:
2 error(s) occurred:
* Resource 'digitalocean_tag.ponpokopon' does not have attribute 'id' for variable 'digitalocean_tag.ponpokopon.id'
* null_resource.tag_changed_annotation: diffs didn't match during apply. This is a bug with Terraform and should be reported as a GitHub Issue.
Please include the following information in your report:
Terraform Version: 0.8.5
Resource ID: null_resource.tag_changed_annotation
Mismatch reason: attribute mismatch: triggers.value
Diff One (usually from plan): *terraform.InstanceDiff{mu:sync.Mutex{state:0, sema:0x0}, Attributes:map[string]*terraform.ResourceAttrDiff{"triggers.%":*terraform.ResourceAttrDiff{Old:"", New:"1", NewComputed:false, NewRemoved:false, NewExtra:interface {}(nil), RequiresNew:true, Sensitive:false, Type:0x0}, "triggers.value":*terraform.ResourceAttrDiff{Old:"", New:"ponpokopon2", NewComputed:false, NewRemoved:false, NewExtra:interface {}(nil), RequiresNew:true, Sensitive:false, Type:0x0}}, Destroy:false, DestroyDeposed:false, DestroyTainted:false}
Diff Two (usually from apply): *terraform.InstanceDiff{mu:sync.Mutex{state:0, sema:0x0}, Attributes:map[string]*terraform.ResourceAttrDiff{"triggers.%":*terraform.ResourceAttrDiff{Old:"", New:"", NewComputed:true, NewRemoved:false, NewExtra:interface {}(nil), RequiresNew:true, Sensitive:false, Type:0x0}}, Destroy:false, DestroyDeposed:false, DestroyTainted:false}
Also include as much context as you can about your config, state, and the steps you performed to trigger this error.
- また、既に作成したことのあるtagに変更しようとすると下記エラーになる場合がある
module.droplet.digitalocean_tag.ponpokopon: Modifying...
name: "hogehoge" => "ponpokopon"
Error applying plan:
1 error(s) occurred:
* digitalocean_tag.ponpokopon: Failed to update tag: PUT https://api.digitalocean.com/v2/tags/hogehoge: 422 Error processing request to tags server: Both origin and destination tags already exists. Please try again.
感想
多少強引だけどterraformとmackerelを連携させることが出来ました。
以前個人サーバのdnsの設定をいつの間にか変えてしまったことがあり、Githubの変更から変えてしまったタイミングを探したことがありましたが、グラフアノテーションをうまく使ってインフラの変更を時系列で見ていければ便利だなと思いました。
あとは例えばawsのamiやインスタンスタイプを変更した前後でグラフがどう変わるかとか見れたら楽しそう。
今後はansibleとも連携させてみようと思っています。