LoginSignup
22
14

More than 5 years have passed since last update.

AnsibleのJinja2を活用してtemplateモジュールの中で配列をループさせる

Last updated at Posted at 2018-04-18

やりたい事

 with_dictのような機能を使って、templateの中の構文を配列単位でループさせたい

要は…

例:haproxy.conf
backend web1_status
        mode tcp
        balance first
        option tcpka
        option httpchk GET /httpchk.php
        server web1 192.168.111.111:80 check port 80 inter 60s rise 1 fall 1
backend web2_status
        mode tcp
        balance roundrobin
        option tcpka
        option httpchk GET /
        server web2 192.168.222.222:80 check port 80 inter 30s rise 3 fall 1
backend web3_status
        mode tcp
        balance static-rr
        option tcpka
        option httpchk GET /index.html
        server web2 192.168.333.333:80 check port 80 inter 10s rise 5 fall 3

など、ある程度規則性があるものを変数化させループさせたい。

という感じ。
※設定内容はあくまで例となります。

そもそもwith_dictはansibleのモジュールの処理内でループさせるものでtemplateモジュール内の特定の1ファイル内に対してはループができなさそう。(個人的見解です)

似たようなものでuseraddモジュールをwith_dictを使ってループさせたりはしていたのだがそれとも違う。

tasks/useradd.yml
---
- name: ユーザ作成
  user:
    name: "{{ item.key }}"
    uid: "{{ item.value.uid }}"
    group: "{{ item.value.group }}"
    groups: "{{ item.value.groups }}"
    password: "{{ item.value.password }}"
    shell: "{{ item.value.shell}}"
    home: "{{ item.value.home}}"
  with_dict: "{{ users }}"
  no_log: true
vars/useradd.yml
users:
  aaa:
      uid: 1
      password: *****
      group: aaa
      groups:
      shell: "/bin/bash"
      home: "/home/aaa"
  bbb:
      uid: 222
      password: *****
      group: bbb
      groups: wheel
      shell: "/bin/bash"
      home: "/home/bbb"

また、1項目のみの変数化でいいのであれば以下のような感じでできるけどそれも違う。

templates/nginx.conf
{% if server=='aaa' %}
{% for web_ip in nginx.web_ips %}
    server {{ web_ip }}:80 max_fails=2 fail_timeout=300s;
{% endfor %}
vars/vars.yml
nginx:
  web_ips:
    - 192.168.111.111
    - 192.168.222.222

という事で1日中試行錯誤した結果できたのが以下。

結果

tasks/main.yml
- name: 設定ファイル設置
  template: src=haproxy.conf dest=/etc/haproxy/haproxy.conf owner=root group=root mode=0644
templates/haproxy.conf
{% if inventory_directory=='haproxy' %}
{% for item in web_services %}
backend {{ web_services[item].name }}_status
        mode tcp
        balance {{ web_services[item].balance }}
        option tcpka
        option httpchk GET {{ web_services[item].url }}
        server {{ web_services[item].name }} {{ web_services[item].ip }}:80 check port 80 inter {{ web_services[item].inter }} rise {{ web_services[item].rise }} fall {{ web_services[item].fall }}
{% endfor %}
{% endif %}
vars/vars.yml
web_services:
  web1:
    name: web1
    balance: first
    url: /httpchk.php
    ip: 192.168.111.111
    inter: 60s
    rise: 1
    fall: 1
  web2:
    name: web2
    balance: roundrobin
    url: /
    ip: 192.168.222.222
    inter: 30s
    rise: 3
    fall: 1
  web3:
    name: web3
    balance: static-rr
    url: /index.html
    ip: 192.168.333.333
    inter: 10s
    rise: 5
    fall: 3

※参考にしたのはこれ
jinja2 - Loop dictionary in ansible template - Stack Overflow

上の記事も今回やりたいことと目的が違ったが配列をtempalteに落とし込む際には使えそうだったので参考にさせて頂きました。

とりあえず久しぶりにansibleと格闘して途中諦めかけたがなんとかできてよかった…。

もっと他に効率のいい方法などあれば教えて下さい。

課題

課題としてはfor文での出力がトップダウン方式ではなくでランダムになってしまう場合がある。(ある程度規則性はあるのだろうが不明)

varsには

web1:
web2:
web3:

で書いたのに
出力が

web3:
web1:
web2:

のようになってしまう。※実際の文字列はもう少し不規則なもの
現状問題はないができれば順番に出したい。
というか前にもおんなじことではまってた気がする。

一旦web1:の部分を1:のように数字順にする事で解決できたが、何かいい解決策はないだろうか…。

22
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
14