Skip to content

Instantly share code, notes, and snippets.

@ssato
Created March 25, 2020 18:14
Show Gist options
  • Save ssato/caa87f2e141d0d28854e62b6cca006f7 to your computer and use it in GitHub Desktop.
Save ssato/caa87f2e141d0d28854e62b6cca006f7 to your computer and use it in GitHub Desktop.
Ansibleの呼吸 肆ノ型 フィルター芸「0,1反転」- 別解: Jinja2 Macro 編

はじめに

この投稿は Ansible 3 Advent Calendar 2019 の七日目の記事です。

ここでは @sky_jokerxx さんの五日目の記事 Ansibleの呼吸 肆ノ型 フィルター芸「0,1反転」 の別解を Jinja2 の macro を使って実装してみます。(なおまた別の @akira6592 さんの別解はこちらに: [Ansible] 【別解】 Ansibleの呼吸 肆ノ型 フィルター芸「0,1反転」)

使用するファイル

御二方の記事とまったく同じように入力ファイルを用意します。 内容は同じなので手順は割愛します。

Playbook

---
- hosts: localhost
  connection: local
  gather_facts: false
  vars:
    input: >-
      {{ lookup('file', 'before_number.txt') }}
  tasks:
    - name: Compute the result
      set_fact:
        _result: >-
         {% macro inv(s) -%}
         {%   for c in s | list -%}
         {%     if c == '0' %}1{%
                elif c == '1' %}0{%
                else -%}
         {{       c -}}
         {%     endif -%}
         {%   endfor -%}
         {% endmacro -%}
         {{ inv(input) }}

    - name: Output the computed result
      copy:
        content: |
          {{ _result }}
        dest: after_number.txt
        force: false

# vim:sw=2:ts=2:et:
  1. 他記事と同様に変数 input に入力ファイルの内容を読み込んだ文字列を代入
  2. 文字列を受け取って一文字毎に処理 (if .. endif 部分) して '0' は '1' に '1' は '0' に変換、他はそのままにするような Jinja2 Macro inv を定義
  3. Jinja2 Macro inv に変数 input (文字列) を処理させ、結果 (文字列)を得て変数 _result に代入
  4. 変数 _result の内容を出力ファイルに出力

set_fact で変数 _result の内容として Jinja2 Macor 定義 ( {% macro ~ {% endmacro -%}) と Macro の呼び出し ( inv(input) 行) を続けて書くのがポイントです。

また Macro 定義部分では、結果の文字列に余計な改行が含まれてしまわないよう '-' を利用 ('-}}' や '-%}') したり、節の途中で意図的に改行したりしています (参考: Jinja2 Template Designer Documentation: Whitespace Control)。

Playbook 実行

$ cat inv.yml
---
- hosts: localhost
  connection: local
  gather_facts: false
  vars:
    input: >-
      {{ lookup('file', 'before_number.txt') }}
  tasks:
    - name: Compute the result
      set_fact:
        _result: >-
         {% macro inv(s) -%}
         {%   for c in s | list -%}
         {%     if c == '0' %}1{%
                elif c == '1' %}0{%
                else -%}
         {{       c -}}
         {%     endif -%}
         {%   endfor -%}
         {% endmacro -%}
         {{ inv(input) }}

    - name: Output the computed result
      copy:
        content: |
          {{ _result }}
        dest: after_number.txt
        force: false

# vim:sw=2:ts=2:et:
$ ansible-playbook inv.yml

PLAY [localhost] ***************************************************************************************************

TASK [Compute the result] ******************************************************************************************
ok: [localhost]

TASK [Output the computed result] **********************************************************************************
changed: [localhost]

PLAY RECAP *********************************************************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

$ cat after_number.txt
110101010101010101101010
000111010101011000101100
011110101011110101010101
001010101010101101010101
010101011010101010101111
000000011111000101111111
$

Jinj2 Macro の利用はしばしば Ansible Playbook の難読化の向上に大きく貢献しますが場合によっては非常に強力かもしれません。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment