あれ、どうやったっけ

(たぶん)テキストサイト風blog。文が安定するまで書き直しあるからメンゴ。

【素人瞬殺】 Jinja2 feat. Ansible vs Predictable Network Interface Names 【Jinja2殺】

chef13触ったものの、Ansibleのほうが楽かなぁと思った結果、jinja2に処刑される。

  • お題:(DHCPとかで)IPだけは見当つくマシンに対して固定IP振りたいんです

なんで? って言われると「ラズパイ何台か並べてて分散処理させたい」が、あとで「あのdeb入れなきゃいけなかったんか」と気づいた時に一括で挿入れられるようにしたいじゃないですかdebを。体格がおすもうさんの人を押し込めるわけじゃないけど……。

さらに言うと、わざわざNICの設定個別にするのだるい(たぶん数回はinterfaces周りの設定間違える)じゃないですか。僕だけですけど。

ここはダイナミックインベントリを悪用しつつDHCPとかでIP持ってるのをAnsible側で良しなに判断して固定インターフェースなファイル吐かし、以後は固定IPのインベントリを使っていこうという方法を。「楽」ってのは「たぶんミス率下がるし、たぶん後でオペ数減る(はず)」程度の意味。

入る入らないじゃねえ、挿入れるんだよ(なんかのエロ同人誌で見た名言)

に従えば、ハナっからSSHだけできるようにRaspbian LiteとNOOBS設定して、Predictable Network Interface Names(Cent君7とかでNICの名前がenxsXpXXになるアレ)を考慮しつつansibleでよしなにするのがベターであろう、と。

で、残念な結果に。

main.yml(タスク)

---
- name: get interface name
  set_fact:
    phys_devs: "{% set phys_devs = phys_devs|default([]) + [hostvars[inventory_hostname]['ansible_' + item]] %}{{ phys_devs|list }}"
  when: "ansible_{{item | replace('-', '_')}}.module is defined"
  with_items: "{{ansible_interfaces}}"
  
- name: generate nic conf
  become: yes
  template:
    src: wired.conf.j2
    dest: /etc/network/interfaces.d/wired.conf

wired.conf.j2 (テンプレート)

{# jinja2 do not support rewriting variable from inner scope(ex: "for" loop) to outer scope. #}
{# Let's hack, "set _ = list.append(x)". "set _" means dummy(fake expression). #}
{% for device in phys_devs %}
{%   set selected_nic = [none] %}
{%   for item_nic in nics %}
{%     if device.module is defined and item_nic.module == device.module %}
{%       set _ = selected_nic.pop() %}
{%       set _ = selected_nic.append(item_nic) %}
{%     endif %}
{%   endfor %}
{%   set nic = selected_nic[0] %}
{%   if nic is none %}
iface {{ device.device }} inet manual

{%   else %}
allow-hotplug {{ device.device }}
iface {{ device.device }} inet static
    address {{ nic.ip }}
    netmask {{ nic.netmask }}
    broadcast {{ nic.broadcast }}
    gateway {{ nic.gateway }}
{%     if nic.dns_nameservers is defined %}
    dns-nameservers {{ nic.dns_nameservers }}
{%     endif %}
{%     if nic.dns_search is defined %}
    dns-search {{ nic.dns_search }}
{%     endif %}

{%   endif %}
{% endfor %}

NICの設定ファイル吐かすタスクのmain.yml、「phys_devs: ~」行に大量のウンコマーク付きそうで死にたい。元ネタは海外のサイトでかっぱらってきたコード片、URL忘れた。

やってることは「factをlistでくるんで代入して、listでくるんだのと新しいfactをまたlistでくるんで代入」の繰り返し。jinja2先生もう許してください。っていうか分かれよ

あとループ外の変数をループ内でsetしても上書きできないjinja2の設計に泣かされる。

具体的には「forでナメて一個抜いて後続処理」なネスト軽減芸がめんどいことは罪なので罰としてエビ抜いたエビ天をあげますJinja2の中の人に。

ブロックの内側でブロックの外の変数書き換えるの Jinja1系では出来たことじゃないんですかね? なんて思うんですけど、なんで2で出来なくしたのかはわからん。

個人とか小規模でそれなりにイケてるプロビジョンなブツないんかしら? スクリプト書いとけってことになりそうだけど。