Itamae で firewalld を操作する itamae-plugin-resource-firewalld

[gongo/itamae-plugin-resource-firewalld](https://github.com/gongo/itamae-plugin-resource-firewalld)

## 経緯

- 訳あって CentOS 7 の provisioning の手順をコードに落としたくなり、最近熱いという噂の [Itamae](https://github.com/ryotarai/itamae) でやってみたくなった。
- しかし、CentOS 7 からは慣れ親しんだ `iptables` コマンドではなく `firewalld` という野郎が表に出てきたということらしい
- [itamae-plugin-resource-iptables](https://github.com/eagletmt/itamae-plugin-resource-iptables) であれば存在するが `firewalld` 用は無かった。[execute resource](https://github.com/ryotarai/itamae/wiki/Resources-execute) をがんばって繋げていけばもちろんできるが美しくない

    ```rb
    # recipe.rb
    execute 'firewall-cmd --zone public --add-service http'
    execute 'firewall-cmd --zone public --remove-service dhcpv6-client'
    ```

    こんな感じになってしまう。シェルスクリプトで良さそう。

というわけで firewalld 用 resource plugin を書こうと思いました。

### Recipe Plugin について

当初 [Resource Plugin](https://github.com/ryotarai/itamae/wiki/Resource-Plugins) or [Recipe Plugin](https://github.com/ryotarai/itamae/wiki/Recipe-Plugins) で考えていましたが、recipe は既存の resource を組合せていくイメージで、結局中で `execute` を連ねていきそうだったので、せっかくだからということで新しい resource を生み出すことにしました。

## Firewalld とは

https://fedorahosted.org/firewalld/

## Usage

### Zone configuration

```rb
service 'firewalld' do
  action [:start, :enable]
end

firewalld_zone 'public' do
  interfaces %w(eth0)
  services   %w(ssh https mysql)
  ports      %w(8080/tcp 4243/udp)

  masquerade   true
  default_zone true

  notifies :restart, 'service[firewalld]'
end
```

こいつを実行するとこんな感じになります。

```
$ sudo firewall-cmd --list-all --zone public
public (default, active)
  interfaces: eth0
  sources:
  services: https mysql ssh
  ports: 4243/udp 8080/tcp
  masquerade: yes
  forward-ports:
  icmp-blocks:
  rich rules:
```

### Service define

その他の機能としては、独自サービスの追加:

```rb
firewalld_service 'my-ssh' do
  short       'my-ssh'
  description 'My ssh that customized port'
  protocol    'tcp'
  port        '2222'
end

# 削除する時はこんな感じ
# firewalld_service 'my-ssh' do
#   action :delete
# end
```

実行後、対象マシンに `/etc/firewalld/services/my-ssh.xml` が作成される

```xml
<?xml version='1.0' encoding='UTF-8'?>
<service>
  <short>my-ssh</short>
  <description>My ssh that customized port</description>
  <port port='2222' protocol='tcp'/>
</service>
```

## [おまけ] テストについて

`itamae-plugin-resource-xxx` 系のテスト、どうやって書けばいいんだろうと悩んでいます。

- ひとまず [itamae/spec/unit/lib/itamae/resource/base_spec.rb](https://github.com/ryotarai/itamae/blob/master/spec/unit/lib/itamae/resource/base_spec.rb#L88-L118) をちら見
- いくつか存在する resource plugin のリポジトリを覗いてみてもテストが無い

あまり量は無い感じ。最終的には ↓ こんな感じで落ち着きました。

[itamae-plugin-resource-firewalld/test/itamae/plugin/resource](https://github.com/gongo/itamae-plugin-resource-firewalld/tree/v0.0.2/test/itamae/plugin/resource)

assert 系はほぼ使わず、最後に到達する `run_command` や `run_specinfra` に **期待する引数が渡されるか** というところに重点を起きました。(結果に関しては関与しない。Itamae や Specinfra の `run_command` 系メソッドに任せる形で)

### 余談ですが

普段は RSpec でテスト書いてますが、今回は

test-unit + [mocha](https://github.com/freerange/mocha)

で行いました。[test-unit-rr](https://github.com/test-unit/test-unit-rr/) が一般的なのかな?と思いましたが。とりあえずお試しも兼ねて。今のところ RSpec 並に書けて無問題。

## まとめ

`Itamae` 便利だし :sushi: 食いたい

## 参考

- [Ruby - itamae resourceの書き方 - Qiita](http://qiita.com/k0kubun/items/b41e004004390a8f07d7)
- [Itamae で firewalld を操作する plugin をリリースしました - Thanks Driven Life](http://gongo.hatenablog.com/entry/2014/12/22/083051)
    - 自分のブログでは、中身についてちょっとだけ付け加えています