何周遅れかわかりませんが、Route53のDNSレコードをコードでできるroadworkerでいろいろやってみたのでメモ。
Rubyとroadworkerのバージョンは以下のとおりです。
$ ruby -v ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin19] $ roadwork -v roadwork 0.5.14
目次
変数
単純に変数を定義して参照するだけです。文字列としてクォート内で参照する場合には#{変数名}
で。
domain = "example.com" default_ttl = 100 hosted_zone domain do rrset "www.#{domain}", "A" do ttl default_ttl resource_records( "192.168.0.1" ) end end
結果
レコード名 | タイプ | 値 | TTL |
---|---|---|---|
www.example.com | A | 192.168.0.1 | 100 |
ループ
eachを使って単純なループをさせる場合。数値計算も普通にできますね。
domain = "example.com" default_ttl = 100 hosted_zone domain do (1..9).each do |n| rrset "www#{n}.#{domain}", "A" do ttl default_ttl + 200 resource_records( "192.168.1.#{n}" ) end end end
結果
レコード名 | タイプ | 値 | TTL |
---|---|---|---|
www1.example.com | A | 192.168.1.1 | 300 |
www2.example.com | A | 192.168.1.2 | 300 |
www3.example.com | A | 192.168.1.3 | 300 |
www4.example.com | A | 192.168.1.4 | 300 |
www5.example.com | A | 192.168.1.5 | 300 |
www6.example.com | A | 192.168.1.6 | 300 |
www7.example.com | A | 192.168.1.7 | 300 |
www8.example.com | A | 192.168.1.8 | 300 |
www9.example.com | A | 192.168.1.9 | 300 |
配列/ハッシュ
配列・ハッシュを組み合わせるこんなこともできます。
domain = "example.com" default_ttl = 100 subnet = "192.168.2" servers = [ { name: "www", record: "#{subnet}.1" }, { name: "mail", record: "#{subnet}.2" }, { name: "app", record: "#{subnet}.3" } ] hosted_zone domain do servers.each do |server| rrset "#{server[:name]}.#{domain}", "A" do ttl default_ttl resource_records( server[:record] ) end end end
結果
レコード名 | タイプ | 値 | TTL |
---|---|---|---|
www.example.com | A | 192.168.2.1 | 100 |
mail.example.com | A | 192.168.2.2 | 100 |
app.example.com | A | 192.168.2.3 | 100 |
文字列の結合
普通にrubyの関数が使えるので、文字列結合させて、こんなこともできます。
domain = "example.com" default_ttl = 100 sender_ips = [ "192.168.3.1/32", "192.168.3.2/32", "192.168.3.3/32", "192.168.3.4/32", ] str_txt_record = sender_ips.map{|r| "ip4:" + r}.join(" ") hosted_zone domain do rrset "#{domain}", "TXT" do ttl default_ttl resource_records( "\"v=spf1 #{str_txt_record} ~all\"" ) end end
結果
レコード名 | タイプ | 値 | TTL |
---|---|---|---|
example.com | TXT | "v=spf1 ip4:192.168.3.1/32 ip4:192.168.3.2/32 ip4:192.168.3.3/32 ip4:192.168.3.4/32 ~all" | 100 |
テンプレート
templateを使うと、よく使う設定を使いまわすことができます。
domain = "example.com" default_ttl = 100 template "default_rrset" do rrset context.name + "." + context.hosted_zone_name, "A" do ttl context.ttl resource_records( "192.168.4.1" ) end end hosted_zone domain do context.ttl = default_ttl include_template "default_rrset", :name => "customer1" include_template "default_rrset", :name => "customer2" include_template "default_rrset", :name => "customer3" end
結果
レコード名 | タイプ | 値 | TTL |
---|---|---|---|
customer1.example.com | A | 192.168.4.1 | 100 |
customer2.example.com | A | 192.168.4.1 | 100 |
customer3.example.com | A | 192.168.4.1 | 100 |
hosted_zoneのゾーン名やtemplateに渡す変数に対してcontext.*
でアクセスできるようです。ブロック内の定義はtemplateの外で明示的にcontext.*
と指定しないとtemplateからアクセスできないみたいです。contextがhostedゾーンブロック内のローカル変数って感じなんでしょうか?試しにこう書いてみるといけましたので、多分あってますね。
hosted_zone domain do local_ttl = default_ttl include_template "default_rrset", :name => "customer1", :ttl => local_ttl include_template "default_rrset", :name => "customer2", :ttl => local_ttl include_template "default_rrset", :name => "customer3", :ttl => local_ttl end
テスト
-t
でテストができますが、更新時とかは特に失敗することが多いと思います。
$ roadwork -a Apply `Routefile` to Route53 === Change batch: example.com. | /hostedzone/XXXXXXXXXXXXXX Create ResourceRecordSet: customer1.example.com. A Create ResourceRecordSet: customer2.example.com. A Create ResourceRecordSet: customer3.example.com. A --> Change submitted: /change/XXXXXXXXXXXXXXXXXXXXX $ roadwork -t FFF customer1.example.com. A: Query timed out customer2.example.com. A: Dnsruby::NXDomain customer3.example.com. A: Dnsruby::NXDomain 3 examples, 3 failures
通常は(プロバイダ等の)キャッシュDNSサーバに聞きに行くと思いますが、変更前のキャッシュがまだ残っていたりする場合などですね(上記の例だとネガティブキャッシュが残ってるのだと思います)。こういう場合は権威DNSサーバ、つまりRoute53で割り当てられたNSレコードのDNSサーバに直接聞けばよいです。
$ dig example.com ns +short ns-XXXX.awsdns-XX.org. ns-XXXX.awsdns-XX.co.uk. ns-XXX.awsdns-XX.com. ns-XXX.awsdns-XX.net. $ roadwork -t --nameservers ns-XXXX.awsdns-XX.org ... 3 examples, 0 failure
あと設定があっている場合は上記のようにあまり出力されないようなのですが、--debug
をつけるとテストっぽい出力が追加されるのでこっちのほうが良い感じがします。
$ roadwork -t --nameservers ns-XXXX.awsdns-XX.org --debug opening connection to route53.amazonaws.com:443... opened starting SSL for route53.amazonaws.com:443... (...いろいろ内部処理が表示される。割愛...) Check DNS: customer1.example.com. A expected=192.168.4.1(100) actual=192.168.4.1(100) Check DNS: customer2.example.com. A expected=192.168.4.1(100) actual=192.168.4.1(100) Check DNS: customer3.example.com. A expected=192.168.4.1(100) actual=192.168.4.1(100) 3 examples, 0 failure
roadwork -t
は事後のテストですけど、事前のテストはどうするのがよいんでしょうか?RubyだとRSpecとかになるのかな?
まとめ
Rubyが書ければいろいろ凝ったこともできそうですが、やりすぎると何やってるかパッと見でわかりにくくなったり、DSLの意味が薄れるかなという気がします。CI/CD回してテストで担保できるようにすればいいかもしれませんね。
参考)