今日は、Defined Typeの使い所を考えます。
Defined Type とは
公式の例を整形 && 少しわかりやすく変更。硬式の記法がまるっきりPuppet4なので、慣れている3互換で失礼しますね...
define apache::vhost (
$port,
$docroot,
$servername = $title,
$vhost_name = '*'
) {
include apache # Package['httpd'] と Service['httpd'] が定義されている
include apache::params # 下の $apache::params::vhost_dir が定義されている
$vhost_dir = $apache::params::vhost_dir
file { "${vhost_dir}/${servername}.conf":
content => template('apache/vhost-${servername}.conf.erb'),
# パラメータとして定義した変数名を普通に使えるし、テンプレート内部でも使える
owner => 'www',
group => 'www',
mode => '644',
require => Package['httpd'],
notify => Service['httpd'],
}
}
特定のType操作の組み合わせを、新しいTypeとして定義する機能です。この例では、Apacheのvhostごとのサーバ設定を独立したTypeとして定義していますね。
わかる人向けには、ChefでいうLWRP的なものです。
具体例をもう少し
Consul KVの値を、べき等に登録するには、以下のようにcurlのコマンドを利用して記述できます。
$key = 'Foo'
$value = 'Bar'
exec { "curl -X PUT -d '${value}' http://localhost:850/v1/kv${key}":
unless => "test \"$(curl http://localhost:850/v1/kv${key}?raw)\" = '${value}'";
}
このcurl、何をやっているのかわかりづらいので、 consul::kvs
という名前をつけてあげるとわかりやすく、しかも使い回しもできるようになるという感じです。
define consul::kvs (
$key = $name,
$value = '',
$consul_master_host = 'localhost:8500'
) {
exec { "curl -X PUT -d '${value}' http://${consul_master_host}/v1/kv${key}":
unless => "test \"$(curl http://${consul_master_host}/v1/kv${key}?raw)\" = '${value}'";
}
}
consul::kvs {
'Foo':
value => 'Bar';
'XXX':
value => 'YYY';
#...
}
考察
便利機能ですが、幾つか癖があります
- 適切な名前付けをしないと、何をするものか分かりづらくなりがち
- 外部依存するクラスが多すぎると、依存関係の解決がすっきりしない
最初のvhostの例は、 include/require もいいんですが、 宇宙船演算子 を用いて以下のような書き方のほうがわかりやすいかもしれません。
Package['httpd']
-> Apache::Vhost<| |>
~> Service['httpd']
個人的には、Defined Typeは単純に「DRYにするぞ!!1」と濫用するものではないように思います。
その定義すべきTypeが、 独立したリソースタイプとしてみなせるか ?という観点で考えて、みなしたほうがコードがすっきりするような抽象化ができるのなら、上手に使えるのではないでしょうか。
個人的な経験では、以下のようなものをDefined Typeにしてみたりしました。
- Consul KVの値
- Consulのcheckによる監視項目
-
Mackerel のロール (と言ってもテンプレートで
roles = [ "service:<%= @role_name %>" ]
をファイルに吐き出すだけ) - sysctlで定義するカーネルパラメータ
参考になればと思います。