はじめに
Ansibleを使ってて自分が好きな点が、
手抜きもできるけど、改善して綺麗に書けることです。
そこで、自分が実際にやったリファクタリングを書いてみます。
(内容は脚色しています)
CentOS 7で確認しています。
Ansible以前
最初の手順は以下の通りです。
- /etc/profile に以下の内容を書き込む
if [ "$USER" != "foo" ]; then
export FOO=BAR
fi
ここからスタートです。
まずは素直に実装
Ansibleでそのまま素直に実装すると、blockinfileを使って以下のように書けます。
- name: /etc/profile に環境設定を追加
blockinfile:
path: /etc/profile
block: |
if [ "$USER" != "foo" ]; then
export FOO=BAR
fi
become: yes
このとき、/etc/profileの最後に以下のように書き込まれます。
# BEGIN ANSIBLE MANAGED BLOCK
if [ "$USER" != "foo" ]; then
export FOO=BAR
fi
# END ANSIBLE MANAGED BLOCK
blockinfileはコードの臭い
これでも問題ないです。冪等性は保たれます。
しかし、# BEGIN ANSIBLE MANAGED BLOCK
と
# END ANSIBLE MANAGED BLOCK
が入っているのがなんとなくイヤな感じです。
間違って誰かが消してしまうとおかしくなります。
自分の中では、blockinfileは扱いづらいので、避けるようにしています。
ただ決してこのモジュールが悪いわけではないです。
どこか改良できる点がある、そう感じさせるシグナルです。
いわゆるコードの臭いです。
blockinfile → lineinfile + copy
そこでまず、lineinfileを使うようにしました。
こんな感じです。
- name: foo.shを /etc/profile.foo としてコピー
copy:
src: foo.sh
dest: /etc/profile.foo
become: yes
- name: profile.fooを読み込み
lineinfile:
path: /etc/profile
line: source /etc/profile.foo
become: yes
blockinfileは使わなくなりましたが、2つに分かれてしまい、
何をしたいのか分かりづらくなってしまいました。
lineinfile + copy → copy
しかしそもそも /etc/profile を書き換える必要はありません。
/etc/profile に以下のように記載されているとおり、 /etc/profile.d
以下に
拡張子 .sh または sh.local という名前のファイルを置けば、勝手に読み取ってくれます。
for i in /etc/profile.d/*.sh /etc/profile.d/sh.local ; do
if [ -r "$i" ]; then
if [ "${-#*i}" != "$-" ]; then
. "$i"
else
. "$i" >/dev/null
fi
fi
done
なので、以下のようにファイルコピーだけでOKです。
- name: foo.sh を /etc/profile.d 以下にコピー(bash起動時に読み込まれる)
copy:
src: foo.sh
dest: /etc/profile.d/foo.sh
become: yes
OSの仕組みを知ることで、よりシンプルな書き方ができました。
おわりに
今回は比較的簡単な例でしたが、
Ansibleはコードによる自動化をするだけではなく、改善点を洗い出すために有効です。
例えば failed_when: false
などでごまかしている場合は、
終了コードが0でないプログラムがあります。
fileモジュールで force=yes
をつけている場合は、
そもそも手順が前後している場合があります。
AnsibleはYAMLで書くためプログラマブル要素が低めですが、
それを欠点と捉えるのではなく、改善のためのシグナルを提供していると考えればいいと思います。
だから自分はAnsibleを使ってて楽しいです( ´ω`)